From 06e84d876725b697cfaebb4c95ee723a633744e7 Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:15:27 +0100 Subject: [PATCH 01/61] Fix delete button being disabled after use --- .../custom_levels/custom_level_editor.py | 12 ++++++++---- .../ui/levels/shared/palette_panel.py | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py index 161c836d..2b0fba7e 100644 --- a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py +++ b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py @@ -657,16 +657,16 @@ def add_tilecode(self, tile, percent, alt_tile): return ref_tile def delete_tilecode(self, tile_name, tile_code): + if tile_name == r"empty": + tkMessageBox.showinfo("Uh Oh!", "Can't delete empty!") + return False + msg_box = tk.messagebox.askquestion( "Delete Tilecode?", "Are you sure you want to delete this Tilecode?\nAll of its placements will be replaced with air.", icon="warning", ) if msg_box == "yes": - if tile_name == r"empty": - tkMessageBox.showinfo("Uh Oh!", "Can't delete empty!") - return - new_tile = self.tile_palette_map["0"] for matrix_index, tile_code_matrix in enumerate(self.tile_codes): for row in range(len(tile_code_matrix)): @@ -689,6 +689,10 @@ def delete_tilecode(self, tile_name, tile_code): self.log_codes_left() self.changes_made() + + return True + else: + return False def log_codes_left(self): codes = "" diff --git a/src/modlunky2/ui/levels/shared/palette_panel.py b/src/modlunky2/ui/levels/shared/palette_panel.py index 6fdaade8..f8c594ff 100644 --- a/src/modlunky2/ui/levels/shared/palette_panel.py +++ b/src/modlunky2/ui/levels/shared/palette_panel.py @@ -102,7 +102,7 @@ def __init__( self.delete_button = tk.Button( self, - text="Del", + text="Delete", bg="red", fg="white", width=10, @@ -143,9 +143,10 @@ def tile_name(self): def tile_code(self): return self.name.split(" ", 1)[1] - def reset(self): + def reset(self, disable=True): self.select_tile("empty 0", None) - self.disable() + if disable: + self.disable() def enable(self): self.delete_button["state"] = tk.NORMAL @@ -193,11 +194,12 @@ def __init__( self.new_tile_panel.grid(row=3, column=0, sticky="swne") def delete_tilecode(self, tile_name, tile_code): - self.on_delete_tilecode(tile_name, tile_code) - if self.primary_tile_view.tile_code() == tile_code: - self.primary_tile_view.reset() - if self.secondary_tile_view.tile_code() == tile_code: - self.secondary_tile_view.reset() + deleted = self.on_delete_tilecode(tile_name, tile_code) + if deleted: + if self.primary_tile_view.tile_code() == tile_code: + self.primary_tile_view.reset(disable=False) + if self.secondary_tile_view.tile_code() == tile_code: + self.secondary_tile_view.reset(disable=False) def update_with_palette(self, new_palette, suggestions, biome, lvl): for widget in self.palette.scrollable_frame.winfo_children(): From 4b5f776c9a769b858cdbfd98e96f7af373a33f62 Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Tue, 5 Dec 2023 01:53:10 +0100 Subject: [PATCH 02/61] Add keyboard shortcut for selecting tiles For the first ten tiles in the palette, press a number key to set the primary tile or alt + number key to set the secondary tile --- .../custom_levels/custom_level_editor.py | 2 +- .../ui/levels/shared/palette_panel.py | 37 +++++++++++++++---- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py index 2b0fba7e..eddb74b3 100644 --- a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py +++ b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py @@ -689,7 +689,7 @@ def delete_tilecode(self, tile_name, tile_code): self.log_codes_left() self.changes_made() - + return True else: return False diff --git a/src/modlunky2/ui/levels/shared/palette_panel.py b/src/modlunky2/ui/levels/shared/palette_panel.py index f8c594ff..f4272efa 100644 --- a/src/modlunky2/ui/levels/shared/palette_panel.py +++ b/src/modlunky2/ui/levels/shared/palette_panel.py @@ -164,7 +164,7 @@ def __init__( texture_fetcher, sprite_fetcher, *args, - **kwargs + **kwargs, ): super().__init__(parent, *args, **kwargs) @@ -205,15 +205,19 @@ def update_with_palette(self, new_palette, suggestions, biome, lvl): for widget in self.palette.scrollable_frame.winfo_children(): widget.destroy() + TILES_PER_ROW = 8 + count_row = 0 count_col = -1 self.tile_images = [] used_tile_names = [] + for tile_keep in new_palette: - if count_col == 7: - count_col = -1 + count_col += 1 + if count_col == TILES_PER_ROW: + count_col = 0 count_row = count_row + 1 - count_col = count_col + 1 + tile_name = tile_keep[0].split(" ", 2)[0] used_tile_names.append(tile_name) @@ -236,6 +240,18 @@ def update_with_palette(self, new_palette, suggestions, biome, lvl): lambda event, r=count_row, c=count_col: self.tile_pick(event, r, c), ) + # Bind first ten tiles to number keys + tile_index = count_col + (count_row * TILES_PER_ROW) + 1 + if tile_index <= 10: + self.bind_all( + f"{tile_index%10}", + lambda event, r=count_row, c=count_col: self.tile_pick(event, r, c), + ) + self.bind_all( + f"", + lambda event, r=count_row, c=count_col: self.tile_pick(event, r, c), + ) + if suggestions and len(suggestions): count_col = -1 self.palette.scrollable_frame.rowconfigure(count_row + 1, minsize=15) @@ -250,10 +266,12 @@ def update_with_palette(self, new_palette, suggestions, biome, lvl): if suggestion in used_tile_names: # Do not suggest a tile that already exists in the palette. continue - if count_col == 7: - count_col = -1 + + count_col += 1 + if count_col == TILES_PER_ROW: + count_col = 0 count_row = count_row + 1 - count_col = count_col + 1 + tile_image = ImageTk.PhotoImage( self.texture_fetcher.get_texture(suggestion, biome, lvl, 40) ) @@ -284,8 +302,11 @@ def update_with_palette(self, new_palette, suggestions, biome, lvl): self.new_tile_panel.enable() def tile_pick(self, event, row, col): + if not self.palette.scrollable_frame.grid_slaves(row, col): + return selected_tile = self.palette.scrollable_frame.grid_slaves(row, col)[0] - self.select_tile(selected_tile["text"], selected_tile["image"], event.num == 1) + is_primary = (event.num == 1) or (event.state & 0x20000 == 0) + self.select_tile(selected_tile["text"], selected_tile["image"], is_primary) def suggested_tile_pick(self, event, suggested_tile, tile_image): tile = self.on_add_tilecode(suggested_tile, 100, "empty") From 2f7bf1e693a85bbbe11ec4f38614bd8d6f36186c Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:52:02 +0100 Subject: [PATCH 03/61] Fix Olmec Ship cutscene gem tracker issue Going from Tiamat to Sunken City does two extra level transitions (6-4 => 6-1 => 6-4 => 7-1). These should be excluded (they have the BASE_CAMP theme). --- src/modlunky2/ui/trackers/gem.py | 5 ++++- src/modlunky2/ui/trackers/pacino_golf_tracker.py | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modlunky2/ui/trackers/gem.py b/src/modlunky2/ui/trackers/gem.py index 5ae15c9f..f640d9e8 100644 --- a/src/modlunky2/ui/trackers/gem.py +++ b/src/modlunky2/ui/trackers/gem.py @@ -210,6 +210,7 @@ def poll(self, proc: Spel2Process, config: GemTrackerConfig) -> WindowData: return None level_has_ghost = game_state.theme not in [ + Theme.BASE_CAMP, Theme.OLMEC, Theme.ABZU, Theme.DUAT, @@ -223,7 +224,9 @@ def poll(self, proc: Spel2Process, config: GemTrackerConfig) -> WindowData: level = game_state.level # On level change - if world != self.world or level != self.level: + if ( + world != self.world or level != self.level + ) and game_state.theme != Theme.BASE_CAMP: # Update world and level self.world = world self.level = level diff --git a/src/modlunky2/ui/trackers/pacino_golf_tracker.py b/src/modlunky2/ui/trackers/pacino_golf_tracker.py index 531e3476..777ac7b5 100644 --- a/src/modlunky2/ui/trackers/pacino_golf_tracker.py +++ b/src/modlunky2/ui/trackers/pacino_golf_tracker.py @@ -248,7 +248,9 @@ def poll(self, proc: Spel2Process, config: PacinoGolfTrackerConfig) -> WindowDat level = game_state.level # Save treasure strokes on level change - if world != self.world or level != self.level: + if ( + world != self.world or level != self.level + ) and game_state.theme != Theme.BASE_CAMP: self.world = world self.level = level self.treasure_strokes += self.treasure_strokes_level From 7d70ddf8cf917f65b081abe82fa87b45c53a3723 Mon Sep 17 00:00:00 2001 From: Dregu Date: Sat, 16 Dec 2023 06:00:30 +0200 Subject: [PATCH 04/61] Autofill local install pack name with source file stem --- requirements.txt | 1 + src/modlunky2/ui/install.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 330d78b9..85c36d8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ starlette==0.31.1 typing_extensions==4.8.0 websockets==11.0.3 zstandard==0.21.0 +python-tkdnd==0.2.1 diff --git a/src/modlunky2/ui/install.py b/src/modlunky2/ui/install.py index 0e9ea22c..d99357af 100644 --- a/src/modlunky2/ui/install.py +++ b/src/modlunky2/ui/install.py @@ -33,7 +33,9 @@ def __init__(self, parent, modlunky_config: Config): font="sans 11 bold", ).grid(row=0, column=0, padx=5, sticky="ew") - file_chooser_label = ttk.Label(self, text="Choose the file you want to install") + file_chooser_label = ttk.Label( + self, text="Choose the file you want to install (.zip, .lua, .png...)" + ) file_chooser_label.grid( row=1, column=0, padx=5, pady=(2, 0), columnspan=3, sticky="w" ) @@ -84,7 +86,10 @@ def __init__(self, parent, modlunky_config: Config): text="Destination", font="sans 11 bold", ).grid(row=0, column=0, padx=5, sticky="ew") - file_chooser_label = ttk.Label(self, text="Choose or Create a Pack") + file_chooser_label = ttk.Label( + self, + text="Choose or create a new folder for the pack (defaults to source file name)", + ) file_chooser_label.grid( row=1, column=0, padx=5, pady=(2, 0), columnspan=3, sticky="w" ) @@ -239,6 +244,9 @@ def render(self): dest = self.file_chooser_frame2.file_chooser_var.get() if source and dest: self.button_install["state"] = tk.NORMAL + elif source: + self.file_chooser_frame2.file_chooser_var.set(Path(source).stem) + self.button_install["state"] = tk.NORMAL else: self.button_install["state"] = tk.DISABLED From 9b5e77fa580881b80b8262027511410941e436e4 Mon Sep 17 00:00:00 2001 From: Dregu Date: Sat, 16 Dec 2023 07:35:36 +0200 Subject: [PATCH 05/61] Add drag&drop support and simple name input for local installation --- src/modlunky2/ui/__init__.py | 11 ++++++++-- src/modlunky2/ui/install.py | 40 ++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/modlunky2/ui/__init__.py b/src/modlunky2/ui/__init__.py index dffb487e..8b6041d7 100644 --- a/src/modlunky2/ui/__init__.py +++ b/src/modlunky2/ui/__init__.py @@ -4,8 +4,10 @@ import time import tkinter as tk import traceback +import tkinterDnD from tkinter import PhotoImage, ttk from multiprocessing import Queue +from pathlib import Path from modlunky2.constants import BASE_DIR, IS_EXE from modlunky2.updater import self_update @@ -103,7 +105,8 @@ def __init__(self, modlunky_config: Config, log_level=logging.INFO): "modlunky2:latest_version", self.handle_modlunky_latest_version ) - self.root = tk.Tk(className="Modlunky2") + self.root = tkinterDnD.Tk(className="Modlunky2") + self.load_themes() style = ttk.Style(self.root) self.root.default_theme = style.theme_use() @@ -170,7 +173,7 @@ def __init__(self, modlunky_config: Config, log_level=logging.INFO): self.root.bind("", self.quit) self.tabs = {} - self.tab_control = ttk.Notebook(self.top_frame) + self.tab_control = ttk.Notebook(self.top_frame, onfiledrop=self.drop) logger.debug("Registering Tabs") self.register_tab( @@ -262,6 +265,10 @@ def __init__(self, modlunky_config: Config, log_level=logging.INFO): self.check_for_updates() self.check_requirements() + def drop(self, event): + self.tabs["Install Mods"].local_install.drop_file(event.data) + self.tab_control.select(1) + def check_for_updates(self): if self.needs_update: return diff --git a/src/modlunky2/ui/install.py b/src/modlunky2/ui/install.py index d99357af..1793bc7d 100644 --- a/src/modlunky2/ui/install.py +++ b/src/modlunky2/ui/install.py @@ -34,7 +34,8 @@ def __init__(self, parent, modlunky_config: Config): ).grid(row=0, column=0, padx=5, sticky="ew") file_chooser_label = ttk.Label( - self, text="Choose the file you want to install (.zip, .lua, .png...)" + self, + text="Drop a file anywhere or choose file to install (.zip, .lua, .png...)", ) file_chooser_label.grid( row=1, column=0, padx=5, pady=(2, 0), columnspan=3, sticky="w" @@ -88,7 +89,7 @@ def __init__(self, parent, modlunky_config: Config): ).grid(row=0, column=0, padx=5, sticky="ew") file_chooser_label = ttk.Label( self, - text="Choose or create a new folder for the pack (defaults to source file name)", + text="Enter new pack name or choose existing pack", ) file_chooser_label.grid( row=1, column=0, padx=5, pady=(2, 0), columnspan=3, sticky="w" @@ -99,7 +100,6 @@ def __init__(self, parent, modlunky_config: Config): file_chooser_entry = ttk.Entry( self, textvariable=self.file_chooser_var, - state=tk.DISABLED, ) file_chooser_entry.columnconfigure(0, weight=1) file_chooser_entry.columnconfigure(1, weight=1) @@ -197,14 +197,15 @@ def __init__(self, parent, modlunky_config: Config, task_manager, *args, **kwarg ) self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) + self.rowconfigure(0, weight=10000) self.rowconfigure(1, weight=1) - self.rowconfigure(2, minsize=60) + self.rowconfigure(2, weight=1) + self.rowconfigure(3, minsize=60) source_frame = ttk.Frame(self) source_frame.rowconfigure(0, weight=1) source_frame.columnconfigure(0, weight=1) - source_frame.grid(row=0, column=0, pady=5, sticky="nswe") + source_frame.grid(row=1, column=0, pady=5, sticky="nswe") self.file_chooser_frame = SourceChooser(source_frame, modlunky_config) self.file_chooser_frame.grid(row=0, column=0, pady=5, sticky="new") @@ -212,13 +213,17 @@ def __init__(self, parent, modlunky_config: Config, task_manager, *args, **kwarg dest_frame = ttk.Frame(self) dest_frame.rowconfigure(0, weight=1) dest_frame.columnconfigure(0, weight=1) - dest_frame.grid(row=1, column=0, pady=5, sticky="nswe") + dest_frame.grid(row=2, column=0, pady=5, sticky="nswe") self.file_chooser_frame2 = DestinationChooser(dest_frame, modlunky_config) self.file_chooser_frame2.grid(row=0, column=0, pady=5, sticky="new") - self.button_install = ttk.Button(self, text="Install", command=self.install) - self.button_install.grid(row=2, column=0, pady=5, padx=5, sticky="nswe") + self.button_install = ttk.Button( + self, + text="Select source and destination or drop a file anywhere", + command=self.install, + ) + self.button_install.grid(row=3, column=0, pady=5, padx=5, sticky="nswe") def install(self): source = Path(self.file_chooser_frame.file_chooser_var.get()) @@ -244,11 +249,28 @@ def render(self): dest = self.file_chooser_frame2.file_chooser_var.get() if source and dest: self.button_install["state"] = tk.NORMAL + self.button_install["text"] = "Install selected file to existing pack" elif source: self.file_chooser_frame2.file_chooser_var.set(Path(source).stem) self.button_install["state"] = tk.NORMAL + self.button_install["text"] = "Install selected file as new pack" else: self.button_install["state"] = tk.DISABLED + self.button_install[ + "text" + ] = "Select source and destination or drop a file anywhere" + + def drop_file(self, data): + files = self.file_chooser_frame.tk.splitlist(data) + if files[0] and Path(files[0]).exists(): + logger.info( + "Click 'Install' in the right column to complete installation of %s", + Path(files[0]).name, + ) + self.file_chooser_frame.file_chooser_var.set(Path(files[0])) + self.file_chooser_frame2.file_chooser_var.set(Path(files[0]).stem) + self.button_install["state"] = tk.NORMAL + self.button_install["text"] = "Install dropped file as new pack" def write_manifest(dest_dir: Path, mod_details, mod_file, logo=None): From a114584660d6c943810ee3165d182cf487fa3aae Mon Sep 17 00:00:00 2001 From: Dregu Date: Sat, 16 Dec 2023 07:39:37 +0200 Subject: [PATCH 06/61] cleanup --- src/modlunky2/ui/__init__.py | 4 ++-- src/modlunky2/ui/install.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modlunky2/ui/__init__.py b/src/modlunky2/ui/__init__.py index 8b6041d7..dcfa31d1 100644 --- a/src/modlunky2/ui/__init__.py +++ b/src/modlunky2/ui/__init__.py @@ -4,10 +4,10 @@ import time import tkinter as tk import traceback -import tkinterDnD from tkinter import PhotoImage, ttk from multiprocessing import Queue -from pathlib import Path + +import tkinterDnD from modlunky2.constants import BASE_DIR, IS_EXE from modlunky2.updater import self_update diff --git a/src/modlunky2/ui/install.py b/src/modlunky2/ui/install.py index 1793bc7d..e4d7d31a 100644 --- a/src/modlunky2/ui/install.py +++ b/src/modlunky2/ui/install.py @@ -262,7 +262,7 @@ def render(self): def drop_file(self, data): files = self.file_chooser_frame.tk.splitlist(data) - if files[0] and Path(files[0]).exists(): + if files[0] and Path(files[0]).exists() and Path(files[0]).is_file(): logger.info( "Click 'Install' in the right column to complete installation of %s", Path(files[0]).name, From f74708208b04ce4bb476429b7f0d0ec4d8198842 Mon Sep 17 00:00:00 2001 From: Dregu Date: Sat, 16 Dec 2023 09:09:34 +0200 Subject: [PATCH 07/61] Update existing pack check live --- src/modlunky2/ui/__init__.py | 2 +- src/modlunky2/ui/install.py | 32 +++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/modlunky2/ui/__init__.py b/src/modlunky2/ui/__init__.py index dcfa31d1..863f52b7 100644 --- a/src/modlunky2/ui/__init__.py +++ b/src/modlunky2/ui/__init__.py @@ -266,8 +266,8 @@ def __init__(self, modlunky_config: Config, log_level=logging.INFO): self.check_requirements() def drop(self, event): - self.tabs["Install Mods"].local_install.drop_file(event.data) self.tab_control.select(1) + self.tabs["Install Mods"].local_install.drop_file(event.data) def check_for_updates(self): if self.needs_update: diff --git a/src/modlunky2/ui/install.py b/src/modlunky2/ui/install.py index e4d7d31a..a95b182e 100644 --- a/src/modlunky2/ui/install.py +++ b/src/modlunky2/ui/install.py @@ -100,6 +100,11 @@ def __init__(self, parent, modlunky_config: Config): file_chooser_entry = ttk.Entry( self, textvariable=self.file_chooser_var, + validate="all", + ) + file_chooser_entry["validatecommand"] = ( + file_chooser_entry.register(self.changed), + "%P", ) file_chooser_entry.columnconfigure(0, weight=1) file_chooser_entry.columnconfigure(1, weight=1) @@ -111,6 +116,10 @@ def __init__(self, parent, modlunky_config: Config): file_chooser_browse = ttk.Button(self, text="Browse", command=self.browse) file_chooser_browse.grid(row=3, column=0, pady=5, padx=5, sticky="nsew") + def changed(self, val): + self.master.master.check_exists(val) + return True + def browse(self): if not self.modlunky_config.install_dir: return @@ -244,16 +253,26 @@ def install(self): pack=pack, ) + def check_exists(self, dest): + dest_path = self.modlunky_config.install_dir / "Mods/Packs" / Path(dest).stem + if not dest: + self.button_install["state"] = tk.DISABLED + return + self.button_install["state"] = tk.NORMAL + if dest_path.exists(): + self.button_install["text"] = "Install selected file to existing pack" + else: + self.button_install["text"] = "Install selected file as new pack" + def render(self): source = self.file_chooser_frame.file_chooser_var.get() dest = self.file_chooser_frame2.file_chooser_var.get() - if source and dest: - self.button_install["state"] = tk.NORMAL - self.button_install["text"] = "Install selected file to existing pack" - elif source: + if source and not dest: self.file_chooser_frame2.file_chooser_var.set(Path(source).stem) + dest = self.file_chooser_frame2.file_chooser_var.get() + if source and dest: self.button_install["state"] = tk.NORMAL - self.button_install["text"] = "Install selected file as new pack" + self.check_exists(dest) else: self.button_install["state"] = tk.DISABLED self.button_install[ @@ -269,8 +288,7 @@ def drop_file(self, data): ) self.file_chooser_frame.file_chooser_var.set(Path(files[0])) self.file_chooser_frame2.file_chooser_var.set(Path(files[0]).stem) - self.button_install["state"] = tk.NORMAL - self.button_install["text"] = "Install dropped file as new pack" + self.render() def write_manifest(dest_dir: Path, mod_details, mod_file, logo=None): From 8959f95e69f826eefda71df87df703c130065b77 Mon Sep 17 00:00:00 2001 From: Dregu Date: Sat, 16 Dec 2023 09:24:05 +0200 Subject: [PATCH 08/61] Fix pack exist check with empty source --- src/modlunky2/ui/install.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/modlunky2/ui/install.py b/src/modlunky2/ui/install.py index a95b182e..bd3967de 100644 --- a/src/modlunky2/ui/install.py +++ b/src/modlunky2/ui/install.py @@ -117,7 +117,9 @@ def __init__(self, parent, modlunky_config: Config): file_chooser_browse.grid(row=3, column=0, pady=5, padx=5, sticky="nsew") def changed(self, val): - self.master.master.check_exists(val) + self.master.master.check_exists( + self.master.master.file_chooser_frame.file_chooser_var.get(), val + ) return True def browse(self): @@ -253,9 +255,15 @@ def install(self): pack=pack, ) - def check_exists(self, dest): + def check_exists(self, source, dest): + source_path = Path(source) dest_path = self.modlunky_config.install_dir / "Mods/Packs" / Path(dest).stem - if not dest: + if ( + not dest + or not source + or not source_path.exists() + or not source_path.is_file() + ): self.button_install["state"] = tk.DISABLED return self.button_install["state"] = tk.NORMAL @@ -272,7 +280,7 @@ def render(self): dest = self.file_chooser_frame2.file_chooser_var.get() if source and dest: self.button_install["state"] = tk.NORMAL - self.check_exists(dest) + self.check_exists(source, dest) else: self.button_install["state"] = tk.DISABLED self.button_install[ From da5fa912b05e6f57d012a56be7c708163656b581 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 21:19:00 -0700 Subject: [PATCH 09/61] Create the multi room editor tab. --- .../multi_room/multi_room_editor_tab.py | 200 ++++++++++++++++++ .../vanilla_levels/multi_room/room_map.py | 48 +++++ .../multi_room/template_draw_item.py | 10 + .../vanilla_levels/vanilla_level_editor.py | 39 ++-- .../ui/levels/vanilla_levels/vanilla_types.py | 25 +++ 5 files changed, 299 insertions(+), 23 deletions(-) create mode 100644 src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py create mode 100644 src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py create mode 100644 src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py create mode 100644 src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py new file mode 100644 index 00000000..c7aec2d8 --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -0,0 +1,200 @@ +from dataclasses import dataclass +import tkinter as tk +from tkinter import ttk + +from modlunky2.config import Config +from modlunky2.levels.level_templates import TemplateSetting +from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer +from modlunky2.ui.levels.shared.palette_panel import PalettePanel +from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom +from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap +from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import TemplateDrawItem +from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate + + +class MultiRoomEditorTab(ttk.Frame): + def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, *args, **kwargs): + super().__init__(parent, *args, **kwargs) + self.modlunky_config = modlunky_config + self.texture_fetcher = texture_fetcher + + # self.on_edit_room = on_edit_room + self.on_add_tilecode = on_add_tilecode + self.on_delete_tilecode = on_delete_tilecode + + self.lvl = None + self.lvl_biome = None + self.tile_palette_map = {} + self.room_templates = [] + self.template_draw_map = [] + + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + + # View that contains the canvases to edit the level along with some controls. + editor_view = tk.Frame(self) + editor_view.grid(row=0, column=0, sticky="news") + self.editor_container = editor_view + + editor_view.columnconfigure(0, weight=1) + editor_view.columnconfigure(2, minsize=0) + editor_view.columnconfigure(1, minsize=50) + editor_view.rowconfigure(1, weight=1) + + self.canvas = MultiCanvasContainer( + editor_view, + textures_dir, + ["Foreground", "Background"], + 50, + self.canvas_click, + self.canvas_shiftclick, + intro_text="Select a level file to begin viewing", + ) + self.canvas.grid(row=0, column=0, columnspan=3, rowspan=2, sticky="news") + self.canvas.show_intro() + + # Side panel with the tile palette and level settings. + side_panel = tk.Frame(self) + side_panel.grid(column=1, row=0, rowspan=2, sticky="news") + side_panel.rowconfigure(0, weight=1) + side_panel.columnconfigure(0, weight=1) + + # Allow hiding the side panel so more level can be seen. + side_panel_hidden = False + side_panel_hide_button = tk.Button(editor_view, text=">>") + + def toggle_panel_hidden(): + nonlocal side_panel_hidden + side_panel_hidden = not side_panel_hidden + if side_panel_hidden: + side_panel.grid_remove() + side_panel_hide_button.configure(text="<<") + else: + side_panel.grid() + side_panel_hide_button.configure(text=">>") + + side_panel_hide_button.configure( + command=toggle_panel_hidden, + ) + side_panel_hide_button.grid(column=1, row=0, sticky="nwe") + + side_panel_tab_control = ttk.Notebook(side_panel) + side_panel_tab_control.grid(row=0, column=0, sticky="nswe") + + self.palette_panel = PalettePanel( + side_panel_tab_control, + self.delete_tilecode, + self.add_tilecode, + self.texture_fetcher, + self.texture_fetcher.sprite_fetcher, + ) + # self.options_panel = OptionsPanel( + # side_panel_tab_control, + # modlunky_config, + # self.zoom_level, + # self.select_theme, + # self.update_level_size, + # self.set_current_save_format, + # self.canvas.hide_grid_lines, + # self.canvas.hide_room_lines, + # self.update_zoom, + # ) + side_panel_tab_control.add(self.palette_panel, text="Tiles") + # side_panel_tab_control.add(self.options_panel, text="Settings") + + def open_lvl(self, lvl, biome, tile_palette_map, room_templates): + self.lvl = lvl + self.lvl_biome = biome + self.tile_palette_map = tile_palette_map + self.room_templates = room_templates + + self.canvas.clear() + self.show_intro() + self.template_draw_map = find_roommap(room_templates) + self.draw_canvas() + + def populate_tilecode_palette(self, tile_palette, suggestions): + self.palette_panel.update_with_palette( + tile_palette, + suggestions, + self.lvl_biome, + self.lvl, + ) + + def add_tilecode(self, tile, percent, alt_tile): + print("Add") + self.on_add_tilecode(tile, percent, alt_tile) + + def delete_tilecode(self, tile_name, tile_code): + print("Delete") + self.on_delete_tilecode(tile_name, tile_code) + + def canvas_click(self, canvas_index, row, column, is_primary): + print("canvas click") + + def canvas_shiftclick(self, canvas_index, row, column, is_primary): + print("canvas shiftclick") + + def show_intro(self): + self.canvas.show_intro() + self.editor_container.columnconfigure(2, minsize=0) + + def hide_intro(self): + self.canvas.hide_intro() + self.editor_container.columnconfigure(2, minsize=17) + + def draw_canvas(self): + if len(self.template_draw_map) == 0: + return + if len(self.template_draw_map[0]) == 0: + return + height = len(self.template_draw_map) + width = len(self.template_draw_map[0]) + + self.canvas.clear() + self.hide_intro() + self.canvas.configure_size(width, height) + + self.canvas.draw_background(self.lvl_biome) + self.canvas.draw_grid() + self.canvas.draw_room_grid() + + # Draws all of the images of a layer on its canvas, and stores the images in + # the proper index of tile_images so they can be removed from the grid when + # replaced with another tile. + def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): + for row_index, room_row in enumerate(tile_codes): + if row_index + chunk_start_y >= height * 8: + continue + for tile_index, tile in enumerate(room_row): + if tile_index + chunk_start_x >= width * 10: + continue + tilecode = self.tile_palette_map[tile] + tile_name = tilecode[0].split(" ", 1)[0] + tile_image = tilecode[1] + x_offset, y_offset = self.texture_fetcher.adjust_texture_xy( + tile_image.width(), + tile_image.height(), + tile_name, + 50 ,# self.zoom_level + ) + self.canvas.replace_tile_at( + canvas_index, + row_index + chunk_start_y, + tile_index + chunk_start_x, + tile_image, + x_offset, + y_offset, + ) + + for room_row_index, room_row in enumerate(self.template_draw_map): + for room_column_index, template_draw_item in enumerate(room_row): + if template_draw_item: + chunk = template_draw_item.room_chunk + front = chunk.front + back = chunk.back + if TemplateSetting.ONLYFLIP in chunk.settings: + front = list(map(lambda row: row[::-1], front)) + back = list(map(lambda row: row[::-1], back)) + draw_chunk(0, room_column_index * 10, room_row_index * 8, front) + draw_chunk(1, room_column_index * 10, room_row_index * 8, back) \ No newline at end of file diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py new file mode 100644 index 00000000..c3d376eb --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -0,0 +1,48 @@ +from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom +from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate +from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import TemplateDrawItem + +def find_roommap(templates): + setrooms = {} + for room_template in templates: + matched_template = Setroom.find_vanilla_setroom(room_template.name) + if matched_template: + if matched_template.name not in setrooms: + setrooms[matched_template.name] = [] + setrooms[matched_template.name].append(MatchedSetroomTemplate(room_template, matched_template)) + # if not matched_template: + # continue + + # setrooms.append(MatchedSetroomTemplate(room_template, matched_template)) + + + def expand_to_height_if_necessary(room_map, height): + if len(room_map) < height: + for _ in range(height - len(room_map)): + if len(room_map) == 0: + room_map.append([None]) + else: + room_map.append([None for _ in range(len(room_map[0]))]) + + def expand_to_width_if_necessary(room_map, width): + for row in room_map: + if len(row) < width: + for _ in range(width - len(row)): + row.append(None) + + room_map = [] + setroom_start = 0 + + for _, setroomtype in setrooms.items(): + for matchedtemplate in setroomtype: + match = matchedtemplate.setroom + x, y = match.coords.x, match.coords.y + + expand_to_height_if_necessary(room_map, y + setroom_start + 1) + expand_to_width_if_necessary(room_map, x + 1) + + room_map[setroom_start + y][x] = TemplateDrawItem(matchedtemplate.template, templates.index(matchedtemplate.template), matchedtemplate.template.rooms[0], 0) + + setroom_start = len(room_map) + + return room_map \ No newline at end of file diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py new file mode 100644 index 00000000..82545105 --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass + +from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate + +@dataclass +class TemplateDrawItem: + template: RoomTemplate + template_index: int + room_chunk: RoomInstance + room_index: int \ No newline at end of file diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 05b6b27d..3bad68dc 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -7,7 +7,6 @@ from pathlib import Path from PIL import Image, ImageTk import pyperclip -import re import tkinter as tk from tkinter import ttk import tkinter.messagebox as tkMessageBox @@ -30,7 +29,9 @@ from modlunky2.ui.levels.vanilla_levels.dual_util import make_dual, remove_dual from modlunky2.ui.levels.vanilla_levels.level_list_panel import LevelListPanel from modlunky2.ui.levels.vanilla_levels.level_settings_bar import LevelSettingsBar +from modlunky2.ui.levels.vanilla_levels.multi_room.multi_room_editor_tab import MultiRoomEditorTab from modlunky2.ui.levels.vanilla_levels.rules.rules_tab import RulesTab +from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate from modlunky2.ui.levels.vanilla_levels.variables.level_dependencies import ( LevelDependencies, ) @@ -45,28 +46,6 @@ class LAYER: FRONT = 0 BACK = 1 - -@dataclass -class RoomInstance: - name: Optional[str] - settings: List[TemplateSetting] - front: List[List[str]] - back: List[List[str]] - - -@dataclass -class RoomTemplate: - name: str - comment: Optional[str] - rooms: List[RoomInstance] - - -@dataclass -class MatchedSetroomTemplate: - template: RoomTemplate - setroom: MatchedSetroom - - @dataclass class RoomType: name: str @@ -167,6 +146,16 @@ def tab_selected(event): self.tab_control ) # Tab 2 is the actual level editor. self.preview_tab = ttk.Frame(self.tab_control) + self.multi_room_editor_tab = MultiRoomEditorTab( + self.tab_control, + self.modlunky_config, + self.texture_fetcher, + textures_dir, + lambda tile, percent, alt_tile: self.add_tilecode( + tile, percent, alt_tile, self.palette_panel, self.mag + ), + self.delete_tilecode, + ) self.variables_tab = VariablesTab( self.tab_control, self.modlunky_config, @@ -250,6 +239,7 @@ def toggle_hide_grid(): self.tab_control.add(self.editor_tab, text="Level Editor") self.tab_control.add(self.rules_tab, text="Rules") self.tab_control.add(self.preview_tab, text="Full Level View") + self.tab_control.add(self.multi_room_editor_tab, text="Full Level Editor") self.tab_control.add(self.variables_tab, text="Variables (Experimental)") self.editor_tab.columnconfigure(0, minsize=200) # Column 0 = Level List @@ -455,6 +445,7 @@ def read_lvl_file(self, lvl): RoomTemplate(template.name, template.comment, data_rooms) ) self.level_list_panel.set_rooms(self.template_list) + self.multi_room_editor_tab.open_lvl(self.lvl, self.lvl_biome, self.tile_palette_map, self.template_list) def load_full_preview(self): self.list_preview_tiles_ref = [] @@ -512,6 +503,7 @@ def get_setrooms(): for currow, room_row in enumerate(layer): tile_image_full = None logger.debug("Room row: %s", room_row) + print("Room row: ", room_row) if TemplateSetting.ONLYFLIP in room_instance.settings: room_row = room_row[::-1] for curcol, tile in enumerate(room_row): @@ -565,6 +557,7 @@ def populate_tilecode_palette(self): self.lvl_biome, self.lvl, ) + self.multi_room_editor_tab.populate_tilecode_palette(self.tile_palette_ref_in_use, None) def save_requested(self): if self.save_needed: diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py new file mode 100644 index 00000000..f8528f62 --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass +from typing import List, Optional + +from modlunky2.levels.level_templates import TemplateSetting +from modlunky2.ui.levels.shared.setrooms import MatchedSetroom + +@dataclass +class RoomInstance: + name: Optional[str] + settings: List[TemplateSetting] + front: List[List[str]] + back: List[List[str]] + + +@dataclass +class RoomTemplate: + name: str + comment: Optional[str] + rooms: List[RoomInstance] + + +@dataclass +class MatchedSetroomTemplate: + template: RoomTemplate + setroom: MatchedSetroom \ No newline at end of file From ef67a03bb031a9bc51d845dddbd0fd31f548a886 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 21:33:50 -0700 Subject: [PATCH 10/61] Link multiroom editor and vanilla editor tile palettes. --- .../ui/levels/custom_levels/custom_level_editor.py | 1 + src/modlunky2/ui/levels/shared/palette_panel.py | 11 ++++++++--- .../multi_room/multi_room_editor_tab.py | 10 +++++++++- .../ui/levels/vanilla_levels/vanilla_level_editor.py | 12 ++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py index eddb74b3..470d00d6 100644 --- a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py +++ b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py @@ -159,6 +159,7 @@ def toggle_panel_hidden(): side_panel_tab_control, self.delete_tilecode, self.add_tilecode, + None, self.texture_fetcher, self.texture_fetcher.sprite_fetcher, ) diff --git a/src/modlunky2/ui/levels/shared/palette_panel.py b/src/modlunky2/ui/levels/shared/palette_panel.py index f4272efa..f3dfd9ac 100644 --- a/src/modlunky2/ui/levels/shared/palette_panel.py +++ b/src/modlunky2/ui/levels/shared/palette_panel.py @@ -161,6 +161,7 @@ def __init__( parent, on_delete_tilecode, on_add_tilecode, + on_select_tile, texture_fetcher, sprite_fetcher, *args, @@ -171,6 +172,7 @@ def __init__( self.texture_fetcher = texture_fetcher self.on_delete_tilecode = on_delete_tilecode self.on_add_tilecode = on_add_tilecode + self.on_select_tile = on_select_tile # The tile palettes are loaded into here as buttons with their image # as a tile and text as their value to grab when needed. @@ -306,20 +308,23 @@ def tile_pick(self, event, row, col): return selected_tile = self.palette.scrollable_frame.grid_slaves(row, col)[0] is_primary = (event.num == 1) or (event.state & 0x20000 == 0) - self.select_tile(selected_tile["text"], selected_tile["image"], is_primary) + self.select_tile(selected_tile["text"], selected_tile["image"], is_primary, True) def suggested_tile_pick(self, event, suggested_tile, tile_image): tile = self.on_add_tilecode(suggested_tile, 100, "empty") if not tile: return - self.select_tile(tile[0], tile_image, event.num == 1) + self.select_tile(tile[0], tile_image, event.num == 1, True) - def select_tile(self, tile_name, tile_image, is_primary): + def select_tile(self, tile_name, tile_image, is_primary, tell_delegate = False): tile_view = self.primary_tile_view if not is_primary: tile_view = self.secondary_tile_view tile_view.select_tile(tile_name, tile_image) + if tell_delegate and self.on_select_tile: + self.on_select_tile(tile_name, tile_image, is_primary) + def reset(self): for widget in self.palette.scrollable_frame.winfo_children(): widget.destroy() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index c7aec2d8..ab7dbee2 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -13,7 +13,7 @@ class MultiRoomEditorTab(ttk.Frame): - def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, *args, **kwargs): + def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, on_select_palette_tile, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.modlunky_config = modlunky_config self.texture_fetcher = texture_fetcher @@ -21,6 +21,7 @@ def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_di # self.on_edit_room = on_edit_room self.on_add_tilecode = on_add_tilecode self.on_delete_tilecode = on_delete_tilecode + self.on_select_palette_tile = on_select_palette_tile self.lvl = None self.lvl_biome = None @@ -85,6 +86,7 @@ def toggle_panel_hidden(): side_panel_tab_control, self.delete_tilecode, self.add_tilecode, + self.palette_selected_tile, self.texture_fetcher, self.texture_fetcher.sprite_fetcher, ) @@ -121,6 +123,12 @@ def populate_tilecode_palette(self, tile_palette, suggestions): self.lvl, ) + def palette_selected_tile(self, tile_name, image, is_primary): + self.on_select_palette_tile(tile_name, image, is_primary) + + def select_tile(self, tile_name, image, is_primary): + self.palette_panel.select_tile(tile_name, image, is_primary) + def add_tilecode(self, tile, percent, alt_tile): print("Add") self.on_add_tilecode(tile, percent, alt_tile) diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 3bad68dc..eb3b8efe 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -155,6 +155,7 @@ def tab_selected(event): tile, percent, alt_tile, self.palette_panel, self.mag ), self.delete_tilecode, + self.multiroom_editor_selected_tile, ) self.variables_tab = VariablesTab( self.tab_control, @@ -309,6 +310,7 @@ def toggle_hide_grid(): lambda tile, percent, alt_tile: self.add_tilecode( tile, percent, alt_tile, self.palette_panel, self.mag ), + self.palette_selected_tile, self.texture_fetcher, self.texture_fetcher.sprite_fetcher, ) @@ -382,6 +384,9 @@ def read_lvl_file(self, lvl): tilecode_item[0], tilecode_item[2], False ) + self.multi_room_editor_tab.select_tile(tilecode_item[0], tilecode_item[2], True) + self.multi_room_editor_tab.select_tile(tilecode_item[0], tilecode_item[2], False) + for i in self.tile_palette_ref_in_use: if str(i[0]).split(" ", 1)[1] == str(tilecode.value): self.tile_palette_ref_in_use.remove(i) @@ -559,6 +564,12 @@ def populate_tilecode_palette(self): ) self.multi_room_editor_tab.populate_tilecode_palette(self.tile_palette_ref_in_use, None) + def palette_selected_tile(self, tile_name, image, is_primary): + self.multi_room_editor_tab.select_tile(tile_name, image, is_primary) + + def multiroom_editor_selected_tile(self, tile_name, image, is_primary): + self.palette_panel.select_tile(tile_name, image, is_primary) + def save_requested(self): if self.save_needed: msg_box = tk.messagebox.askquestion( @@ -725,6 +736,7 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): tile = self.tile_palette_map[tile_code] self.palette_panel.select_tile(tile[0], tile[2], is_primary) + self.multi_room_editor_tab.select_tile(tile[0], tile[2], is_primary) # Looks up the expected offset type and tile image size and computes the offset of the tile's anchor in the grid. def offset_for_tile(self, tile_name, tile_code, tile_size): From 35003945062bb0e8075142967de52c9d7c64c00f Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 21:53:09 -0700 Subject: [PATCH 11/61] Use new size format. --- .../levels/vanilla_levels/multi_room/multi_room_editor_tab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index ab7dbee2..d303975e 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -161,7 +161,7 @@ def draw_canvas(self): self.canvas.clear() self.hide_intro() - self.canvas.configure_size(width, height) + self.canvas.configure_size(width * 10, height * 8) self.canvas.draw_background(self.lvl_biome) self.canvas.draw_grid() From bf30e060d170264a95ec5c735e2101339946f71a Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 23:19:07 -0700 Subject: [PATCH 12/61] Implement canvas actions. --- .../multi_room/multi_room_editor_tab.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index d303975e..10113313 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -139,9 +139,55 @@ def delete_tilecode(self, tile_name, tile_code): def canvas_click(self, canvas_index, row, column, is_primary): print("canvas click") + tile_name, tile_code = self.palette_panel.selected_tile(is_primary) + x_offset, y_offset = self.offset_for_tile(tile_name, tile_code, 50) + + self.canvas.replace_tile_at( + canvas_index, + row, + column, + self.tile_palette_map[tile_code][1], + x_offset, + y_offset + ) + + room_row, room_col = row // 8, column // 10 + template_draw_item = self.template_draw_map[room_row][room_col] + chunk = template_draw_item.room_chunk + layer = [chunk.front, chunk.back][canvas_index] + tile_row = row - room_row * 8 + tile_col = column - room_col * 10 + if TemplateSetting.ONLYFLIP in chunk.settings: + tile_col = 9 - tile_col + layer[tile_row][tile_col] = tile_code def canvas_shiftclick(self, canvas_index, row, column, is_primary): print("canvas shiftclick") + room_row, room_col = row // 8, column // 10 + template_draw_item = self.template_draw_map[room_row][room_col] + chunk = template_draw_item.room_chunk + layer = [chunk.front, chunk.back][canvas_index] + tile_row = row - room_row * 8 + tile_col = column - room_col * 10 + if TemplateSetting.ONLYFLIP in chunk.settings: + tile_col = 9 - tile_col + + tile_code = layer[tile_row][tile_col] + tile = self.tile_palette_map[tile_code] + + self.palette_panel.select_tile(tile[0], tile[2], is_primary) + self.on_select_palette_tile(tile[0], tile[2], is_primary) + + # Looks up the expected offset type and tile image size and computes the offset of the tile's anchor in the grid. + def offset_for_tile(self, tile_name, tile_code, tile_size): + tile_ref = self.tile_palette_map[tile_code] + if tile_ref: + img = tile_ref[1] + return self.texture_fetcher.adjust_texture_xy( + img.width(), img.height(), tile_name, tile_size + ) + + return 0, 0 def show_intro(self): self.canvas.show_intro() From d13961f652d37a0f6830824485f56f048dca9738 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 23:31:55 -0700 Subject: [PATCH 13/61] Synchronize vanilla editors. --- .../multi_room/multi_room_editor_tab.py | 13 ++++++++----- .../levels/vanilla_levels/vanilla_level_editor.py | 9 ++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 10113313..224b0a84 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -13,7 +13,7 @@ class MultiRoomEditorTab(ttk.Frame): - def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, on_select_palette_tile, *args, **kwargs): + def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, on_select_palette_tile, on_modify_room, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.modlunky_config = modlunky_config self.texture_fetcher = texture_fetcher @@ -22,6 +22,7 @@ def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_di self.on_add_tilecode = on_add_tilecode self.on_delete_tilecode = on_delete_tilecode self.on_select_palette_tile = on_select_palette_tile + self.on_modify_room = on_modify_room self.lvl = None self.lvl_biome = None @@ -115,6 +116,11 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.template_draw_map = find_roommap(room_templates) self.draw_canvas() + def redraw(self): + self.canvas.clear() + self.show_intro() + self.draw_canvas() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( tile_palette, @@ -130,15 +136,12 @@ def select_tile(self, tile_name, image, is_primary): self.palette_panel.select_tile(tile_name, image, is_primary) def add_tilecode(self, tile, percent, alt_tile): - print("Add") self.on_add_tilecode(tile, percent, alt_tile) def delete_tilecode(self, tile_name, tile_code): - print("Delete") self.on_delete_tilecode(tile_name, tile_code) def canvas_click(self, canvas_index, row, column, is_primary): - print("canvas click") tile_name, tile_code = self.palette_panel.selected_tile(is_primary) x_offset, y_offset = self.offset_for_tile(tile_name, tile_code, 50) @@ -160,9 +163,9 @@ def canvas_click(self, canvas_index, row, column, is_primary): if TemplateSetting.ONLYFLIP in chunk.settings: tile_col = 9 - tile_col layer[tile_row][tile_col] = tile_code + self.on_modify_room(template_draw_item) def canvas_shiftclick(self, canvas_index, row, column, is_primary): - print("canvas shiftclick") room_row, room_col = row // 8, column // 10 template_draw_item = self.template_draw_map[room_row][room_col] chunk = template_draw_item.room_chunk diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index eb3b8efe..626cfcc7 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -136,6 +136,8 @@ def tab_selected(event): self.last_selected_tab = str(tab) if str(tab) == "Full Level View": self.load_full_preview() + if str(tab) == "Full Level Editor": + self.multi_room_editor_tab.redraw() self.tab_control.bind("<>", tab_selected) @@ -156,6 +158,7 @@ def tab_selected(event): ), self.delete_tilecode, self.multiroom_editor_selected_tile, + self.multiroom_editor_modified_room, ) self.variables_tab = VariablesTab( self.tab_control, @@ -508,7 +511,6 @@ def get_setrooms(): for currow, room_row in enumerate(layer): tile_image_full = None logger.debug("Room row: %s", room_row) - print("Room row: ", room_row) if TemplateSetting.ONLYFLIP in room_instance.settings: room_row = room_row[::-1] for curcol, tile in enumerate(room_row): @@ -570,6 +572,11 @@ def palette_selected_tile(self, tile_name, image, is_primary): def multiroom_editor_selected_tile(self, tile_name, image, is_primary): self.palette_panel.select_tile(tile_name, image, is_primary) + def multiroom_editor_modified_room(self, template_draw_item): + if template_draw_item.room_chunk == self.current_selected_room: + self.room_select(None) + self.changes_made() + def save_requested(self): if self.save_needed: msg_box = tk.messagebox.askquestion( From 364b2e472abed1acedb403630475d0aca2de2ffc Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 18 Nov 2023 23:43:32 -0700 Subject: [PATCH 14/61] Run formatter. --- .../ui/levels/shared/palette_panel.py | 6 ++-- .../multi_room/multi_room_editor_tab.py | 32 +++++++++++++++---- .../vanilla_levels/multi_room/room_map.py | 25 +++++++++++---- .../multi_room/template_draw_item.py | 9 ++++-- .../vanilla_levels/vanilla_level_editor.py | 27 ++++++++++++---- .../ui/levels/vanilla_levels/vanilla_types.py | 5 +-- 6 files changed, 79 insertions(+), 25 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/palette_panel.py b/src/modlunky2/ui/levels/shared/palette_panel.py index f3dfd9ac..6dc8aece 100644 --- a/src/modlunky2/ui/levels/shared/palette_panel.py +++ b/src/modlunky2/ui/levels/shared/palette_panel.py @@ -308,7 +308,9 @@ def tile_pick(self, event, row, col): return selected_tile = self.palette.scrollable_frame.grid_slaves(row, col)[0] is_primary = (event.num == 1) or (event.state & 0x20000 == 0) - self.select_tile(selected_tile["text"], selected_tile["image"], is_primary, True) + self.select_tile( + selected_tile["text"], selected_tile["image"], is_primary, True + ) def suggested_tile_pick(self, event, suggested_tile, tile_image): tile = self.on_add_tilecode(suggested_tile, 100, "empty") @@ -316,7 +318,7 @@ def suggested_tile_pick(self, event, suggested_tile, tile_image): return self.select_tile(tile[0], tile_image, event.num == 1, True) - def select_tile(self, tile_name, tile_image, is_primary, tell_delegate = False): + def select_tile(self, tile_name, tile_image, is_primary, tell_delegate=False): tile_view = self.primary_tile_view if not is_primary: tile_view = self.secondary_tile_view diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 224b0a84..b363274c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -8,17 +8,35 @@ from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap -from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import TemplateDrawItem -from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate +from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( + TemplateDrawItem, +) +from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( + RoomInstance, + RoomTemplate, + MatchedSetroomTemplate, +) class MultiRoomEditorTab(ttk.Frame): - def __init__(self, parent, modlunky_config: Config, texture_fetcher, textures_dir, on_add_tilecode, on_delete_tilecode, on_select_palette_tile, on_modify_room, *args, **kwargs): + def __init__( + self, + parent, + modlunky_config: Config, + texture_fetcher, + textures_dir, + on_add_tilecode, + on_delete_tilecode, + on_select_palette_tile, + on_modify_room, + *args, + **kwargs + ): super().__init__(parent, *args, **kwargs) self.modlunky_config = modlunky_config self.texture_fetcher = texture_fetcher - # self.on_edit_room = on_edit_room + # self.on_edit_room = on_edit_room self.on_add_tilecode = on_add_tilecode self.on_delete_tilecode = on_delete_tilecode self.on_select_palette_tile = on_select_palette_tile @@ -151,7 +169,7 @@ def canvas_click(self, canvas_index, row, column, is_primary): column, self.tile_palette_map[tile_code][1], x_offset, - y_offset + y_offset, ) room_row, room_col = row // 8, column // 10 @@ -233,7 +251,7 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): tile_image.width(), tile_image.height(), tile_name, - 50 ,# self.zoom_level + 50, # self.zoom_level ) self.canvas.replace_tile_at( canvas_index, @@ -254,4 +272,4 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): front = list(map(lambda row: row[::-1], front)) back = list(map(lambda row: row[::-1], back)) draw_chunk(0, room_column_index * 10, room_row_index * 8, front) - draw_chunk(1, room_column_index * 10, room_row_index * 8, back) \ No newline at end of file + draw_chunk(1, room_column_index * 10, room_row_index * 8, back) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index c3d376eb..91da1a24 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -1,6 +1,13 @@ from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom -from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate -from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import TemplateDrawItem +from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( + RoomInstance, + RoomTemplate, + MatchedSetroomTemplate, +) +from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( + TemplateDrawItem, +) + def find_roommap(templates): setrooms = {} @@ -9,13 +16,14 @@ def find_roommap(templates): if matched_template: if matched_template.name not in setrooms: setrooms[matched_template.name] = [] - setrooms[matched_template.name].append(MatchedSetroomTemplate(room_template, matched_template)) + setrooms[matched_template.name].append( + MatchedSetroomTemplate(room_template, matched_template) + ) # if not matched_template: # continue # setrooms.append(MatchedSetroomTemplate(room_template, matched_template)) - def expand_to_height_if_necessary(room_map, height): if len(room_map) < height: for _ in range(height - len(room_map)): @@ -41,8 +49,13 @@ def expand_to_width_if_necessary(room_map, width): expand_to_height_if_necessary(room_map, y + setroom_start + 1) expand_to_width_if_necessary(room_map, x + 1) - room_map[setroom_start + y][x] = TemplateDrawItem(matchedtemplate.template, templates.index(matchedtemplate.template), matchedtemplate.template.rooms[0], 0) + room_map[setroom_start + y][x] = TemplateDrawItem( + matchedtemplate.template, + templates.index(matchedtemplate.template), + matchedtemplate.template.rooms[0], + 0, + ) setroom_start = len(room_map) - return room_map \ No newline at end of file + return room_map diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py index 82545105..ff633a03 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py @@ -1,10 +1,15 @@ from dataclasses import dataclass -from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate +from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( + RoomInstance, + RoomTemplate, + MatchedSetroomTemplate, +) + @dataclass class TemplateDrawItem: template: RoomTemplate template_index: int room_chunk: RoomInstance - room_index: int \ No newline at end of file + room_index: int diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 626cfcc7..acea2758 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -29,9 +29,15 @@ from modlunky2.ui.levels.vanilla_levels.dual_util import make_dual, remove_dual from modlunky2.ui.levels.vanilla_levels.level_list_panel import LevelListPanel from modlunky2.ui.levels.vanilla_levels.level_settings_bar import LevelSettingsBar -from modlunky2.ui.levels.vanilla_levels.multi_room.multi_room_editor_tab import MultiRoomEditorTab +from modlunky2.ui.levels.vanilla_levels.multi_room.multi_room_editor_tab import ( + MultiRoomEditorTab, +) from modlunky2.ui.levels.vanilla_levels.rules.rules_tab import RulesTab -from modlunky2.ui.levels.vanilla_levels.vanilla_types import RoomInstance, RoomTemplate, MatchedSetroomTemplate +from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( + RoomInstance, + RoomTemplate, + MatchedSetroomTemplate, +) from modlunky2.ui.levels.vanilla_levels.variables.level_dependencies import ( LevelDependencies, ) @@ -46,6 +52,7 @@ class LAYER: FRONT = 0 BACK = 1 + @dataclass class RoomType: name: str @@ -387,8 +394,12 @@ def read_lvl_file(self, lvl): tilecode_item[0], tilecode_item[2], False ) - self.multi_room_editor_tab.select_tile(tilecode_item[0], tilecode_item[2], True) - self.multi_room_editor_tab.select_tile(tilecode_item[0], tilecode_item[2], False) + self.multi_room_editor_tab.select_tile( + tilecode_item[0], tilecode_item[2], True + ) + self.multi_room_editor_tab.select_tile( + tilecode_item[0], tilecode_item[2], False + ) for i in self.tile_palette_ref_in_use: if str(i[0]).split(" ", 1)[1] == str(tilecode.value): @@ -453,7 +464,9 @@ def read_lvl_file(self, lvl): RoomTemplate(template.name, template.comment, data_rooms) ) self.level_list_panel.set_rooms(self.template_list) - self.multi_room_editor_tab.open_lvl(self.lvl, self.lvl_biome, self.tile_palette_map, self.template_list) + self.multi_room_editor_tab.open_lvl( + self.lvl, self.lvl_biome, self.tile_palette_map, self.template_list + ) def load_full_preview(self): self.list_preview_tiles_ref = [] @@ -564,7 +577,9 @@ def populate_tilecode_palette(self): self.lvl_biome, self.lvl, ) - self.multi_room_editor_tab.populate_tilecode_palette(self.tile_palette_ref_in_use, None) + self.multi_room_editor_tab.populate_tilecode_palette( + self.tile_palette_ref_in_use, None + ) def palette_selected_tile(self, tile_name, image, is_primary): self.multi_room_editor_tab.select_tile(tile_name, image, is_primary) diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py index f8528f62..4d945115 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_types.py @@ -1,9 +1,10 @@ from dataclasses import dataclass from typing import List, Optional -from modlunky2.levels.level_templates import TemplateSetting +from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.levels.shared.setrooms import MatchedSetroom + @dataclass class RoomInstance: name: Optional[str] @@ -22,4 +23,4 @@ class RoomTemplate: @dataclass class MatchedSetroomTemplate: template: RoomTemplate - setroom: MatchedSetroom \ No newline at end of file + setroom: MatchedSetroom From fcde9bc69cb25fef044be370a917c95f7119815b Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 00:03:37 -0700 Subject: [PATCH 15/61] Cover unavailable rooms in canvas. --- .../ui/levels/shared/level_canvas.py | 33 +++++++++++++++++-- .../levels/shared/multi_canvas_container.py | 11 ++++--- .../multi_room/multi_room_editor_tab.py | 12 +++++-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/level_canvas.py b/src/modlunky2/ui/levels/shared/level_canvas.py index ebb53b1e..e5e19566 100644 --- a/src/modlunky2/ui/levels/shared/level_canvas.py +++ b/src/modlunky2/ui/levels/shared/level_canvas.py @@ -28,6 +28,7 @@ def __init__( self.room_lines = [] self.cached_bgs = {} + self.cached_bg_overs = {} self.width = 0 self.height = 0 @@ -93,6 +94,7 @@ def shift_click(self, event): def set_zoom(self, zoom_level): self.zoom_level = zoom_level self.cached_bgs = {} + self.cached_bg_overs = {} def replace_tile_at(self, row, column, image, offset_x=0, offset_y=0): if len(self.tile_images) <= row or len(self.tile_images[row]) <= column: @@ -137,7 +139,28 @@ def draw_background(self, theme): anchor="nw", ) - def draw_grid(self): + def draw_background_over_room(self, theme, row, col): + bg_img = self.cached_bg_overs.get(theme) + if not bg_img: + background = self.background_for_theme(theme) + image = Image.open(background).convert("RGBA") + image = image.resize( + (self.zoom_level * 10, self.zoom_level * 8), Image.BILINEAR + ) + enhancer = ImageEnhance.Brightness(image) + im_output = enhancer.enhance(0.2) + bg_img = ImageTk.PhotoImage(im_output) + self.cached_bg_overs[theme] = bg_img + + self.create_image( + col * self.zoom_level * 10, + row * self.zoom_level * 8, + image=bg_img, + anchor="nw", + ) + + + def draw_grid(self, width=1): self.grid_lines = [ self.create_line( i * self.zoom_level, @@ -145,21 +168,23 @@ def draw_grid(self): i * self.zoom_level, self.height * self.zoom_level, fill="#F0F0F0", + width=width, ) for i in range(0, self.width + 2) ] + [ self.create_line( 0, - i * self.zoom_level, + i * self.zoom_level - 1, self.zoom_level * (self.width + 2), i * self.zoom_level, fill="#F0F0F0", + width=width, ) for i in range(0, self.height) ] self.hide_grid_lines(self.grid_hidden) - def draw_room_grid(self): + def draw_room_grid(self, width=1): self.room_lines = [ self.create_line( i * 10 * self.zoom_level, @@ -167,6 +192,7 @@ def draw_room_grid(self): i * 10 * self.zoom_level, self.height * self.zoom_level, fill="#30F030", + width=width, ) for i in range(0, int(self.width / 10)) ] + [ @@ -177,6 +203,7 @@ def draw_room_grid(self): self.zoom_level * self.width, i * 8 * self.zoom_level, fill="#30F030", + width=width, ) for i in range(0, int(self.height / 8)) ] diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 8a56bcc3..0eca2e4c 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -252,13 +252,16 @@ def draw_background(self, theme): for canvas in self.canvases: canvas.draw_background(theme) - def draw_grid(self): + def draw_background_over_room(self, canvas_index, theme, row, col): + self.canvases[canvas_index].draw_background_over_room(theme, row, col) + + def draw_grid(self, width=None): for canvas in self.canvases: - canvas.draw_grid() + canvas.draw_grid(width) - def draw_room_grid(self): + def draw_room_grid(self, width=None): for canvas in self.canvases: - canvas.draw_room_grid() + canvas.draw_room_grid(width) def show_intro(self): if self.intro: diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index b363274c..e6590da0 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -231,8 +231,8 @@ def draw_canvas(self): self.canvas.configure_size(width * 10, height * 8) self.canvas.draw_background(self.lvl_biome) - self.canvas.draw_grid() - self.canvas.draw_room_grid() + self.canvas.draw_grid(2) + self.canvas.draw_room_grid(2) # Draws all of the images of a layer on its canvas, and stores the images in # the proper index of tile_images so they can be removed from the grid when @@ -272,4 +272,10 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): front = list(map(lambda row: row[::-1], front)) back = list(map(lambda row: row[::-1], back)) draw_chunk(0, room_column_index * 10, room_row_index * 8, front) - draw_chunk(1, room_column_index * 10, room_row_index * 8, back) + if TemplateSetting.DUAL in chunk.settings: + draw_chunk(1, room_column_index * 10, room_row_index * 8, back) + else: + self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) + else: + self.canvas.draw_background_over_room(0, self.lvl_biome, room_row_index, room_column_index) + self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) From 8eb51d20b2adb35da649b03ef58c5da5f45236e5 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 01:00:46 -0700 Subject: [PATCH 16/61] Add options panel with configurable zoom to multiroom editor. --- .../multi_room/multi_room_editor_tab.py | 128 +++++++++++++----- .../vanilla_levels/vanilla_level_editor.py | 21 ++- 2 files changed, 113 insertions(+), 36 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index e6590da0..6fdf9cfd 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from PIL import Image, ImageTk import tkinter as tk from tkinter import ttk @@ -7,6 +8,7 @@ from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom +from modlunky2.ui.levels.vanilla_levels.multi_room.options_panel import OptionsPanel from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( TemplateDrawItem, @@ -25,6 +27,8 @@ def __init__( modlunky_config: Config, texture_fetcher, textures_dir, + zoom, + on_zoom_change, on_add_tilecode, on_delete_tilecode, on_select_palette_tile, @@ -36,7 +40,7 @@ def __init__( self.modlunky_config = modlunky_config self.texture_fetcher = texture_fetcher - # self.on_edit_room = on_edit_room + self.on_zoom_change = on_zoom_change self.on_add_tilecode = on_add_tilecode self.on_delete_tilecode = on_delete_tilecode self.on_select_palette_tile = on_select_palette_tile @@ -45,9 +49,12 @@ def __init__( self.lvl = None self.lvl_biome = None self.tile_palette_map = {} + self.tile_image_map = {} self.room_templates = [] self.template_draw_map = [] + self.zoom_level = zoom + self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) @@ -65,7 +72,7 @@ def __init__( editor_view, textures_dir, ["Foreground", "Background"], - 50, + self.zoom_level, self.canvas_click, self.canvas_shiftclick, intro_text="Select a level file to begin viewing", @@ -109,24 +116,44 @@ def toggle_panel_hidden(): self.texture_fetcher, self.texture_fetcher.sprite_fetcher, ) - # self.options_panel = OptionsPanel( - # side_panel_tab_control, - # modlunky_config, - # self.zoom_level, - # self.select_theme, - # self.update_level_size, - # self.set_current_save_format, - # self.canvas.hide_grid_lines, - # self.canvas.hide_room_lines, - # self.update_zoom, - # ) + self.options_panel = OptionsPanel( + side_panel_tab_control, + modlunky_config, + self.zoom_level, + self.canvas.hide_grid_lines, + self.canvas.hide_room_lines, + self.__update_zoom_internal, + ) side_panel_tab_control.add(self.palette_panel, text="Tiles") - # side_panel_tab_control.add(self.options_panel, text="Settings") + side_panel_tab_control.add(self.options_panel, text="Settings") + + def image_for_tile_code(self, tile_code): + tile_name = self.tile_palette_map[tile_code][0].split(" ", 2)[0] + + if tile_name in self.tile_image_map: + return self.tile_image_map[tile_name] + + new_tile_image = ImageTk.PhotoImage(self.texture_fetcher.get_texture( + tile_name, self.lvl_biome, self.lvl, self.zoom_level + )) + + # original_size_tile = self.tile_palette_map[tile_code][1] + # new_tile_image = ImageTk.PhotoImage( + # ImageTk.getimage(original_size_tile) + # .resize( + # (self.zoom_level, self.zoom_level), + # Image.Resampling.LANCZOS, + # ) + # .convert("RGBA") + # ) + self.tile_image_map[tile_name] = new_tile_image + return new_tile_image def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.lvl = lvl self.lvl_biome = biome self.tile_palette_map = tile_palette_map + self.tile_image_map = {} self.room_templates = room_templates self.canvas.clear() @@ -139,6 +166,20 @@ def redraw(self): self.show_intro() self.draw_canvas() + def update_zoom_level(self, zoom): + self.options_panel.update_zoom_level(zoom) + self.__set_zoom(zoom) + + def __update_zoom_internal(self, zoom): + self.on_zoom_change(zoom) + self.__set_zoom(zoom) + + def __set_zoom(self, zoom): + self.zoom_level = zoom + self.canvas.set_zoom(zoom) + self.tile_image_map = {} + self.redraw() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( tile_palette, @@ -160,21 +201,22 @@ def delete_tilecode(self, tile_name, tile_code): self.on_delete_tilecode(tile_name, tile_code) def canvas_click(self, canvas_index, row, column, is_primary): - tile_name, tile_code = self.palette_panel.selected_tile(is_primary) - x_offset, y_offset = self.offset_for_tile(tile_name, tile_code, 50) - - self.canvas.replace_tile_at( - canvas_index, - row, - column, - self.tile_palette_map[tile_code][1], - x_offset, - y_offset, - ) - room_row, room_col = row // 8, column // 10 template_draw_item = self.template_draw_map[room_row][room_col] + + if template_draw_item is None: + # Do not draw on empty room. + return + chunk = template_draw_item.room_chunk + + if canvas_index == 1 and TemplateSetting.DUAL not in chunk.settings: + # Do not draw on backlayer of non-dual room. + return + + tile_name, tile_code = self.palette_panel.selected_tile(is_primary) + x_offset, y_offset = self.offset_for_tile(tile_name, tile_code, self.zoom_level) + layer = [chunk.front, chunk.back][canvas_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 @@ -183,16 +225,37 @@ def canvas_click(self, canvas_index, row, column, is_primary): layer[tile_row][tile_col] = tile_code self.on_modify_room(template_draw_item) + self.canvas.replace_tile_at( + canvas_index, + row, + column, + self.image_for_tile_code(tile_code), + x_offset, + y_offset, + ) + def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 template_draw_item = self.template_draw_map[room_row][room_col] + + if template_draw_item is None: + # Do not attempt to pull tile from empty room. + return + chunk = template_draw_item.room_chunk + + if canvas_index == 1 and TemplateSetting.DUAL not in chunk.settings: + # Do not attempt to pull tile from backlayer of non-dual room. + return + layer = [chunk.front, chunk.back][canvas_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: tile_col = 9 - tile_col + + tile_code = layer[tile_row][tile_col] tile = self.tile_palette_map[tile_code] @@ -201,9 +264,11 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): # Looks up the expected offset type and tile image size and computes the offset of the tile's anchor in the grid. def offset_for_tile(self, tile_name, tile_code, tile_size): - tile_ref = self.tile_palette_map[tile_code] - if tile_ref: - img = tile_ref[1] + # tile_ref = self.tile_palette_map[tile_code] + img = self.image_for_tile_code(tile_code) + # if tile_ref: + # img = tile_ref[1] + if img: return self.texture_fetcher.adjust_texture_xy( img.width(), img.height(), tile_name, tile_size ) @@ -246,12 +311,13 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): continue tilecode = self.tile_palette_map[tile] tile_name = tilecode[0].split(" ", 1)[0] - tile_image = tilecode[1] + # tile_image = tilecode[1] + tile_image = self.image_for_tile_code(tile) x_offset, y_offset = self.texture_fetcher.adjust_texture_xy( tile_image.width(), tile_image.height(), tile_name, - 50, # self.zoom_level + self.zoom_level, ) self.canvas.replace_tile_at( canvas_index, diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index acea2758..e583d103 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -112,6 +112,8 @@ def __init__( self.tile_codes = [] self.template_list = [] + self.mag_full = 30 + self.columnconfigure(0, minsize=200) # Column 0 = Level List self.columnconfigure(0, weight=0) self.columnconfigure(1, weight=1) # Column 1 = Everything Else @@ -155,11 +157,18 @@ def tab_selected(event): self.tab_control ) # Tab 2 is the actual level editor. self.preview_tab = ttk.Frame(self.tab_control) + + def multiroom_zoom_change(new_zoom): + self.mag_full = new_zoom + self.current_value_full.set(new_zoom) + self.multi_room_editor_tab = MultiRoomEditorTab( self.tab_control, self.modlunky_config, self.texture_fetcher, textures_dir, + self.mag_full, + multiroom_zoom_change, lambda tile, percent, alt_tile: self.add_tilecode( tile, percent, alt_tile, self.palette_panel, self.mag ), @@ -197,7 +206,9 @@ def tab_selected(event): self.current_value_full = tk.DoubleVar() def slider_changed(_event): + self.mag_full = int(self.current_value_full.get()) self.load_full_preview() + self.multi_room_editor_tab.update_zoom_level(self.mag_full) config_container = tk.Frame(self.preview_tab) config_container.grid(row=0, column=0, columnspan=2, sticky="nw") @@ -211,7 +222,7 @@ def slider_changed(_event): variable=self.current_value_full, command=slider_changed, ) - self.slider_zoom_full.set(50) + self.slider_zoom_full.set(self.mag_full) self.slider_zoom_full.grid(row=0, column=0, sticky="nw") # Checkbox to toggle the visibility of the grid lines. @@ -239,7 +250,7 @@ def toggle_hide_grid(): self.preview_tab, textures_dir, ["Foreground", "Background"], - 50, + self.mag_full, intro_text="Select a level file to begin viewing", ) self.full_level_preview_canvas.grid( @@ -475,9 +486,9 @@ def load_full_preview(self): level_height = 8 level_width = 8 - mag_full = int(self.slider_zoom_full.get() / 2) + # mag_full = int(self.slider_zoom_full.get()) self.full_level_preview_canvas.clear() - self.full_level_preview_canvas.set_zoom(mag_full) + self.full_level_preview_canvas.set_zoom(self.mag_full) full_size = None if self.files_tree.has_selected_file(): @@ -546,7 +557,7 @@ def get_setrooms(): tile_image = ImageTk.PhotoImage( ImageTk.getimage(tiles[-1][1]) .resize( - (mag_full, mag_full), + (self.mag_full, self.mag_full), Image.Resampling.LANCZOS, ) .convert("RGBA") From 4d722b2ab6fb0777b1019a44d1d943d3339959fa Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 08:57:50 -0700 Subject: [PATCH 17/61] Actually add options panel file. --- .../multi_room/options_panel.py | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py new file mode 100644 index 00000000..e3a43e03 --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -0,0 +1,103 @@ +import tkinter as tk +from tkinter import ttk + +class OptionsPanel(ttk.Frame): + def __init__( + self, + parent, + modlunky_config, + zoom_level, + on_update_hide_grid_lines, + on_update_hide_room_lines, + on_update_zoom_level, + *args, + **kwargs + ): + super().__init__(parent, *args, **kwargs) + + self.modlunky_config = modlunky_config + self.on_update_hide_grid_lines = on_update_hide_grid_lines + self.on_update_hide_room_lines = on_update_hide_room_lines + self.on_update_zoom_level = on_update_zoom_level + + + # self.rowconfigure(2, minsize=20) + # self.rowconfigure(4, minsize=20) + self.columnconfigure(0, minsize=10) + self.columnconfigure(1, weight=1) + self.columnconfigure(2, minsize=10) + + # right_padding = 10 + settings_row = 0 + + + # Checkbox to toggle the visibility of the grid lines. + hide_grid_var = tk.IntVar() + hide_grid_var.set(False) + + def toggle_hide_grid(): + nonlocal hide_grid_var + + self.on_update_hide_grid_lines(hide_grid_var.get()) + + settings_row += 1 + tk.Checkbutton( + self, + text="Hide grid lines", + variable=hide_grid_var, + onvalue=True, + offvalue=False, + command=toggle_hide_grid, + ).grid(row=settings_row, column=1, sticky="nw", pady=5) + + # Checkbox to toggle the visibility of the grid lines on room boundaries. + hide_room_grid_var = tk.IntVar() + hide_room_grid_var.set(False) + + def toggle_hide_room_grid(): + nonlocal hide_room_grid_var + self.on_update_hide_room_lines(hide_room_grid_var.get()) + + settings_row += 1 + tk.Checkbutton( + self, + text="Hide room lines", + variable=hide_room_grid_var, + onvalue=True, + offvalue=False, + command=toggle_hide_room_grid, + ).grid(row=settings_row, column=1, sticky="nw", pady=5) + + settings_row += 1 + grid_size_frame = tk.Frame(self) + grid_size_frame.grid(row=settings_row, column=1, sticky="nw", pady=5) + grid_size_frame.columnconfigure(0, weight=1) + grid_size_var = tk.StringVar() + grid_size_var.set(str(zoom_level)) + grid_size_label_frame = tk.Frame(grid_size_frame) + grid_size_label_frame.grid(row=0, column=0, sticky="nw") + + grid_size_header_label = tk.Label(grid_size_label_frame, text="Zoom:") + grid_size_header_label.grid(row=0, column=0, sticky="nwe") + grid_size_label = tk.Label(grid_size_label_frame, textvariable=grid_size_var) + grid_size_label.grid(row=0, column=1, sticky="nw") + + grid_size_scale = tk.Scale( + grid_size_frame, + from_=10, + to=200, + orient=tk.HORIZONTAL, + variable=grid_size_var, + length=390, + showvalue=False, + ) + grid_size_scale.grid(row=1, column=0, sticky="nwe") + + def update_grid_size(_): + self.on_update_zoom_level(int(grid_size_var.get())) + + grid_size_scale["command"] = update_grid_size + self.grid_size_var = grid_size_var + + def update_zoom_level(self, zoom_level): + self.grid_size_var.set(zoom_level) From 39b5f5e491c3344cb938ad81b26bfbff220fe187 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 09:49:00 -0700 Subject: [PATCH 18/61] Add grid room lines for larger room sizes. --- .../ui/levels/shared/level_canvas.py | 46 ++++++++++--------- .../levels/shared/multi_canvas_container.py | 6 +-- .../multi_room/multi_room_editor_tab.py | 25 +++++----- .../multi_room/template_draw_item.py | 2 + 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/level_canvas.py b/src/modlunky2/ui/levels/shared/level_canvas.py index e5e19566..6ce882a2 100644 --- a/src/modlunky2/ui/levels/shared/level_canvas.py +++ b/src/modlunky2/ui/levels/shared/level_canvas.py @@ -1,3 +1,4 @@ +from dataclasses import dataclass import logging import math import tkinter as tk @@ -9,6 +10,13 @@ logger = logging.getLogger(__name__) +@dataclass +class GridRoom: + row: int + column: int + width: int + height: int + class LevelCanvas(tk.Canvas): def __init__( self, parent, textures_dir, zoom_level, on_click, on_pull_tile, *args, **kwargs @@ -184,29 +192,25 @@ def draw_grid(self, width=1): ] self.hide_grid_lines(self.grid_hidden) - def draw_room_grid(self, width=1): - self.room_lines = [ - self.create_line( - i * 10 * self.zoom_level, - 0, - i * 10 * self.zoom_level, - self.height * self.zoom_level, - fill="#30F030", - width=width, - ) - for i in range(0, int(self.width / 10)) - ] + [ - # for i in range(0, rows * 8): - self.create_line( - 0, - i * 8 * self.zoom_level, - self.zoom_level * self.width, - i * 8 * self.zoom_level, - fill="#30F030", + def draw_room_grid(self, width=1, special_room_sizes: GridRoom=None): + def create_room_boundary_box(row, col, w, h): + self.create_rectangle( + col * 10 * self.zoom_level, + row * 8 * self.zoom_level, + (col + w) * 10 * self.zoom_level - 1 + (width - 1), + (row + h) * 8 * self.zoom_level - 1 + (width - 1), + outline="#30F030", width=width, ) - for i in range(0, int(self.height / 8)) - ] + if special_room_sizes is not None: + self.room_lines = [ + create_room_boundary_box(r.row, r.column, r.width, r.height) for r in special_room_sizes + ] + else: + self.room_lines = [ + create_room_boundary_box(row, col, 1, 1) + for row in range(0, int(self.height / 8)) for col in range(0, int(self.width / 10)) + ] self.hide_room_lines(self.rooms_hidden) def hide_grid_lines(self, hide): diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 0eca2e4c..b050ab4f 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -1,7 +1,7 @@ import tkinter as tk from tkinter import ttk -from modlunky2.ui.levels.shared.level_canvas import LevelCanvas +from modlunky2.ui.levels.shared.level_canvas import LevelCanvas, GridRoom from modlunky2.utils import is_windows @@ -259,9 +259,9 @@ def draw_grid(self, width=None): for canvas in self.canvases: canvas.draw_grid(width) - def draw_room_grid(self, width=None): + def draw_room_grid(self, width=1, special_room_sizes: GridRoom=None): for canvas in self.canvases: - canvas.draw_room_grid(width) + canvas.draw_room_grid(width, special_room_sizes) def show_intro(self): if self.intro: diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 6fdf9cfd..bf2bef3b 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -5,6 +5,7 @@ from modlunky2.config import Config from modlunky2.levels.level_templates import TemplateSetting +from modlunky2.ui.levels.shared.level_canvas import GridRoom from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom @@ -137,15 +138,6 @@ def image_for_tile_code(self, tile_code): tile_name, self.lvl_biome, self.lvl, self.zoom_level )) - # original_size_tile = self.tile_palette_map[tile_code][1] - # new_tile_image = ImageTk.PhotoImage( - # ImageTk.getimage(original_size_tile) - # .resize( - # (self.zoom_level, self.zoom_level), - # Image.Resampling.LANCZOS, - # ) - # .convert("RGBA") - # ) self.tile_image_map[tile_name] = new_tile_image return new_tile_image @@ -296,8 +288,19 @@ def draw_canvas(self): self.canvas.configure_size(width * 10, height * 8) self.canvas.draw_background(self.lvl_biome) - self.canvas.draw_grid(2) - self.canvas.draw_room_grid(2) + self.canvas.draw_grid() + + grid_sizes = [] + for room_row_index, room_row in enumerate(self.template_draw_map): + for room_column_index, template_draw_item in enumerate(room_row): + grid_sizes.append(GridRoom( + room_row_index, + room_column_index, + template_draw_item.width_in_rooms, + template_draw_item.height_in_rooms, + )) + + self.canvas.draw_room_grid(2, grid_sizes) # Draws all of the images of a layer on its canvas, and stores the images in # the proper index of tile_images so they can be removed from the grid when diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py index ff633a03..5681413b 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/template_draw_item.py @@ -13,3 +13,5 @@ class TemplateDrawItem: template_index: int room_chunk: RoomInstance room_index: int + width_in_rooms: int = 1 + height_in_rooms: int = 1 From 26d2dadddceedd9452c174f15bb419133c51dcdd Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 10:16:56 -0700 Subject: [PATCH 19/61] Add editing support for big rooms. --- .../multi_room/multi_room_editor_tab.py | 30 +++++++++++++++---- .../vanilla_levels/multi_room/room_map.py | 24 +++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index bf2bef3b..7d2e83c6 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -194,7 +194,8 @@ def delete_tilecode(self, tile_name, tile_code): def canvas_click(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - template_draw_item = self.template_draw_map[room_row][room_col] + # template_draw_item = self.template_draw_map[room_row][room_col] + template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) if template_draw_item is None: # Do not draw on empty room. @@ -228,7 +229,8 @@ def canvas_click(self, canvas_index, row, column, is_primary): def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - template_draw_item = self.template_draw_map[room_row][room_col] + # template_draw_item = self.template_draw_map[room_row][room_col] + template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) if template_draw_item is None: # Do not attempt to pull tile from empty room. @@ -293,6 +295,8 @@ def draw_canvas(self): grid_sizes = [] for room_row_index, room_row in enumerate(self.template_draw_map): for room_column_index, template_draw_item in enumerate(room_row): + if template_draw_item is None: + continue grid_sizes.append(GridRoom( room_row_index, room_column_index, @@ -344,7 +348,23 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): if TemplateSetting.DUAL in chunk.settings: draw_chunk(1, room_column_index * 10, room_row_index * 8, back) else: - self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) + for r in range(template_draw_item.height_in_rooms): + for c in range(template_draw_item.width_in_rooms): + self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index + r, room_column_index + c) else: - self.canvas.draw_background_over_room(0, self.lvl_biome, room_row_index, room_column_index) - self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) + template, _, _ = self.template_item_at(room_row_index, room_column_index) + if template is None: + self.canvas.draw_background_over_room(0, self.lvl_biome, room_row_index, room_column_index) + self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) + + def template_item_at(self, row, col): + for room_row_index, room_row in enumerate(self.template_draw_map): + if room_row_index > row: + return None + for room_column_index, template_draw_item in enumerate(room_row): + if room_column_index > col: + break + if template_draw_item is None: + continue + if room_row_index + template_draw_item.height_in_rooms - 1 >= row and room_column_index + template_draw_item.width_in_rooms - 1 >= col: + return template_draw_item, room_row_index, room_column_index \ No newline at end of file diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 91da1a24..e7ec7ceb 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -58,4 +58,28 @@ def expand_to_width_if_necessary(room_map, width): setroom_start = len(room_map) + for template_index, room_template in enumerate(templates): + if room_template.name == "machine_bigroom_path": + expand_to_height_if_necessary(room_map, setroom_start + 2) + expand_to_width_if_necessary(room_map, 2) + room_map[setroom_start][0] = TemplateDrawItem( + room_template, + template_index, + room_template.rooms[0], + 0, + 2, + 2, + ) + elif room_template.name == "machine_bigroom_side": + expand_to_height_if_necessary(room_map, setroom_start + 2) + expand_to_width_if_necessary(room_map, 4) + room_map[setroom_start][2] = TemplateDrawItem( + room_template, + template_index, + room_template.rooms[0], + 0, + 2, + 2, + ) + return room_map From 4bfc54ce76c7aeee970ee0c31228bc29ff7b1c2f Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 11:26:51 -0700 Subject: [PATCH 20/61] Add setrooms to full editor. --- .../multi_room/multi_room_editor_tab.py | 6 +- .../vanilla_levels/multi_room/room_map.py | 129 +++++++++++++----- 2 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 7d2e83c6..f1df4578 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -360,11 +360,13 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): def template_item_at(self, row, col): for room_row_index, room_row in enumerate(self.template_draw_map): if room_row_index > row: - return None + return None, None, None for room_column_index, template_draw_item in enumerate(room_row): if room_column_index > col: break if template_draw_item is None: continue if room_row_index + template_draw_item.height_in_rooms - 1 >= row and room_column_index + template_draw_item.width_in_rooms - 1 >= col: - return template_draw_item, room_row_index, room_column_index \ No newline at end of file + return template_draw_item, room_row_index, room_column_index + + return None, None, None \ No newline at end of file diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index e7ec7ceb..99658228 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -1,3 +1,5 @@ +import math + from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( RoomInstance, @@ -8,7 +10,6 @@ TemplateDrawItem, ) - def find_roommap(templates): setrooms = {} for room_template in templates: @@ -19,10 +20,6 @@ def find_roommap(templates): setrooms[matched_template.name].append( MatchedSetroomTemplate(room_template, matched_template) ) - # if not matched_template: - # continue - - # setrooms.append(MatchedSetroomTemplate(room_template, matched_template)) def expand_to_height_if_necessary(room_map, height): if len(room_map) < height: @@ -38,48 +35,106 @@ def expand_to_width_if_necessary(room_map, width): for _ in range(width - len(row)): row.append(None) + def set_room(room_map, x, y, room): + expand_to_height_if_necessary(room_map, y + room.height_in_rooms) + expand_to_width_if_necessary(room_map, x + room.width_in_rooms) + room_map[y][x] = room + room_map = [] setroom_start = 0 + def get_template_draw_item(room_template, index): + chunk_index = 0 + if len(room_template.rooms) == 0: + return None + chunk = room_template.rooms[chunk_index] + if chunk is None or len(chunk.front) == 0: + return None + return TemplateDrawItem( + room_template, + index, + chunk, + chunk_index, + int(math.ceil(len(chunk.front[0]) / 10)), + int(math.ceil(len(chunk.front) / 8)), + ) + + for _, setroomtype in setrooms.items(): for matchedtemplate in setroomtype: match = matchedtemplate.setroom x, y = match.coords.x, match.coords.y - expand_to_height_if_necessary(room_map, y + setroom_start + 1) - expand_to_width_if_necessary(room_map, x + 1) - - room_map[setroom_start + y][x] = TemplateDrawItem( - matchedtemplate.template, - templates.index(matchedtemplate.template), - matchedtemplate.template.rooms[0], - 0, - ) + template_item = get_template_draw_item(matchedtemplate.template, templates.index(matchedtemplate.template)) + if template_item: + set_room(room_map, x, setroom_start + y, template_item) setroom_start = len(room_map) - for template_index, room_template in enumerate(templates): - if room_template.name == "machine_bigroom_path": - expand_to_height_if_necessary(room_map, setroom_start + 2) - expand_to_width_if_necessary(room_map, 2) - room_map[setroom_start][0] = TemplateDrawItem( - room_template, - template_index, - room_template.rooms[0], - 0, - 2, - 2, - ) - elif room_template.name == "machine_bigroom_side": - expand_to_height_if_necessary(room_map, setroom_start + 2) - expand_to_width_if_necessary(room_map, 4) - room_map[setroom_start][2] = TemplateDrawItem( - room_template, - template_index, - room_template.rooms[0], - 0, - 2, - 2, - ) + template_map = {} + for index, room_template in enumerate(templates): + template_item = get_template_draw_item(room_template, index) + if template_item: + template_map[room_template.name] = template_item + + path_start = setroom_start + entrance = template_map.get("entrance") + entrance_drop = template_map.get("entrance_drop") + path = template_map.get("path_normal") + path_drop = template_map.get("path_drop") + path_notop = template_map.get("path_notop") + path_drop_notop = template_map.get("path_drop_notop") + path_exit = template_map.get("exit") + path_exit_notop = template_map.get("exit_notop") + path_wide = template_map.get("machine_wideroom_path") + path_tall = template_map.get("machine_tallroom_path") + path_big = template_map.get("machine_bigroom_path") + + more_rooms_start = path_start + + if entrance: + set_room(room_map, 0, path_start, entrance) + more_rooms_start = path_start + 1 + if path is None: + if entrance_drop: + set_room(room_map, 1, path_start, entrance_drop) + more_rooms_start = path_start + 1 + if path_exit: + set_room(room_map, 2, path_start, path_exit) + more_rooms_start = path_start + 1 + if path_exit_notop: + set_room(room_map, 3, path_start, path_exit_notop) + more_rooms_start = path_start + 1 + else: + cw = 1 + set_room(room_map, 1, path_start, path) + if path_drop: + cw = 2 + set_room(room_map, 2, path_start, path_drop) + if entrance_drop: + set_room(room_map, cw + 1, path_start, entrance_drop) + big_top = 1 + if path_wide: + big_top = 2 + set_room(room_map, 0, path_start + 1, path_wide) + has_big = False + if path_big: + has_big = True + set_room(room_map, 0, path_start + big_top, path_big) + if path_drop_notop: + set_room(room_map, 2, path_start + 1, path_drop_notop) + if path_notop: + set_room(room_map, 2, path_start + 2, path_notop) + if path_tall: + set_room(room_map, 3, path_start + 1, path_tall) + er, ec = 3, 2 + if not has_big: + er, ec = 2, 0 + if path_exit: + set_room(room_map, ec, path_start + er, path_exit) + ec += 1 + if path_exit_notop: + set_room(room_map, ec, path_start + er, path_exit_notop) + more_rooms_start = path_start + er + 1 return room_map From 9be6f957f33f10b0e173f9984be30935315b0243 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 11:46:59 -0700 Subject: [PATCH 21/61] Add challenge special rooms and tiamat's olmecroom. --- .../vanilla_levels/multi_room/room_map.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 99658228..0e9bc08d 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -137,4 +137,52 @@ def get_template_draw_item(room_template, index): set_room(room_map, ec, path_start + er, path_exit_notop) more_rooms_start = path_start + er + 1 + olmecship_room = template_map.get("olmecship_room") + if olmecship_room: + for i, room in enumerate(room_map[more_rooms_start - 1]): + if room is None: + set_room(room_map, i, more_rooms_start - 1, olmecship_room) + break + + challenge_entrance = template_map.get("challenge_entrance") + challenge_special = template_map.get("challenge_special") + challenge_bottom = template_map.get("challenge_bottom") + entrancer, entrancec = None, None + if challenge_entrance: + for i, room in enumerate(room_map[more_rooms_start - 1]): + if room is None: + entrancer, entrancec = more_rooms_start - 1, i + set_room(room_map, i, more_rooms_start - 1, challenge_entrance) + break + if entrancer is None: + entrancer, entrancec = more_rooms_start, 0 + set_room(room_map, 0, more_rooms_start, challenge_entrance) + more_rooms_start += 1 + + bottomr, bottomc = None, None + if challenge_bottom: + if entrancer is not None and entrancec is not None: + set_room(room_map, entrancec, entrancer + 1, challenge_bottom) + bottomr, bottomc = entrancer + 1, entrancec + more_rooms_start += 1 + else: + set_room(room_map, 0, more_rooms_start, challenge_bottom) + bottomr, bottomc = more_rooms_start, 0 + more_rooms_start += 1 + + if challenge_special: + if bottomc is not None and bottomr is not None: + set_room(room_map, bottomc < len(room_map[0]) and bottomc + 1 or bottomc - 1, bottomr, challenge_special) + elif entrancer is not None and entrancec is not None: + cr, cc = entrancer + 1, entrancec + if entrancec < len(room_map[entrancer]) and room_map[entrancer][entrancec + 1] is None: + cr, cc = entrancer, entrancec + 1 + elif entrancec > 0 and room_map[entrancer][entrancec - 1] is None: + cr, cc = entrancer, entrancec - 1 + set_room(room_map, cc, cr, challenge_special) + more_rooms_start = cr + 1 + else: + set_room(room_map, 0, more_rooms_start, challenge_special) + more_rooms_start += 1 + return room_map From 5564b7ea6aa8b59391b89ad227706f7031c6a1ea Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 12:04:51 -0700 Subject: [PATCH 22/61] Add side rooms. --- .../vanilla_levels/multi_room/room_map.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 0e9bc08d..1ab85352 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -185,4 +185,40 @@ def get_template_draw_item(room_template, index): set_room(room_map, 0, more_rooms_start, challenge_special) more_rooms_start += 1 + bigroom_side = template_map.get("machine_bigroom_side") + wideroom_side = template_map.get("machine_wideroom_side") + tallroom_side = template_map.get("machine_tallroom_side") + side = template_map.get("side") + + sideroomsc, sideroomsr = 0, 0 + sider, sidec = 0, 0 + highest_room = 0 + if bigroom_side: + set_room(room_map, 0, more_rooms_start, bigroom_side) + sideroomsc = 2 + sideroomsr = 2 + sider, sidec = 0, 2 + highest_room = 2 + if tallroom_side: + set_room(room_map, sideroomsc, more_rooms_start, tallroom_side) + sideroomsr = 2 + sideroomsc += 1 + sider, sidec = 0, sideroomsc + highest_room = 2 + if wideroom_side: + wider, widec = sideroomsr, 0 + sider, sidec = wider, widec + 2 + if sideroomsc <= 2: + wider, widec = 0, sideroomsc + sider, sidec = wider + 1, widec + if wider + 1 > highest_room: + highest_room = wider + 1 + set_room(room_map, widec, more_rooms_start + wider, wideroom_side) + if side: + set_room(room_map, sidec, more_rooms_start + sider, side) + if sider + 1 > highest_room: + highest_room = sider + 1 + + more_rooms_start += highest_room + return room_map From 9770ba2befa85fb3b521ba594de092a4da0ef135 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 12:41:57 -0700 Subject: [PATCH 23/61] Add random other rooms. --- .../vanilla_levels/multi_room/room_map.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 1ab85352..8ebc671d 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -221,4 +221,102 @@ def get_template_draw_item(room_template, index): more_rooms_start += highest_room + other_vertical_paired_rooms_to_add = [ + ["idol_top", "idol"], + ["udjattop", "udjatentrance"], + ["machine_keyroom", "machine_rewardroom"], + ["cog_altar_top", "altar"], + ["oldhunter_keyroom", "oldhunter_rewardroom"], + ] + + vertical_room_column = 0 + vertical_max_height = 0 + for room_pair in other_vertical_paired_rooms_to_add: + top_room = template_map.get(room_pair[0]) + r = 0 + if top_room: + set_room(room_map, vertical_room_column, more_rooms_start, top_room) + r = 1 + if vertical_max_height == 0: + vertical_max_height = 1 + bottom_room = template_map.get(room_pair[1]) + if bottom_room: + if vertical_max_height < r + 1: + vertical_max_height = r + 1 + set_room(room_map, vertical_room_column, more_rooms_start + r, bottom_room) + if top_room is not None or bottom_room is not None: + vertical_room_column += 1 + + more_rooms_bottom = more_rooms_start + vertical_max_height - 1 + + other_rooms_to_add = [ + "abzu_backdoor", + "lake_normal", + "lake_notop", + "lake_exit", + "lakeoffire_back_entrance", + "lakeoffire_back_exit", + "mothership_entrance", + "mothership_exit", + "mothership_coffin", + "storage_room", + "moai", + "coffin_unlockable", + "coffin_player", + "coffin_player_vertical", + "quest_thief2", + "beehive", + "beehive_entrance", + "blackmarket_entrance", + "blackmarket_exit", + "blackmarket_coffin", + "apep", + "pen_room", + "ghistshop", + "empress_grave", + "vault", + "shop_entrance_up", + "shop_entrance_down", + "diceshop", + "curioshop", + "cavemanshop", + "posse", + "quest_thief1", + "room2", + "passage_horz", + "passage_vert", + "passage_turn", + "ushabti_entrance", + "ushabti_room", + "sisters_room", + "motherstatue_room", + "crashedship_entrance", + "crashedship_entrance_notop", + "anubis_room", + "oldhunter_cursedroom", + ] + + for room_name in other_rooms_to_add: + room = template_map.get(room_name) + added_room = False + if room: + for row in range(more_rooms_start, more_rooms_bottom+1): + if added_room: + break + if len(room_map) <= row: + break + for col, template_item in enumerate(room_map[row]): + if template_item is None: + set_room(room_map, col, row, room) + added_room = True + break + + if not added_room: + if len(room_map) > 0 and len(room_map[0]) < 3: + set_room(room_map, len(room_map[0]), more_rooms_start, room) + else: + more_rooms_start = more_rooms_bottom + 1 + more_rooms_bottom = more_rooms_start + set_room(room_map, 0, more_rooms_start, room) + return room_map From 9b3d75a6f602f62f7bd083357ddc0da5cc6bae51 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 12:44:58 -0700 Subject: [PATCH 24/61] Add multiroom shops --- .../ui/levels/vanilla_levels/multi_room/room_map.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 8ebc671d..c9b676e6 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -222,6 +222,8 @@ def get_template_draw_item(room_template, index): more_rooms_start += highest_room other_vertical_paired_rooms_to_add = [ + ["shop_attic", "shop_entrance_up"], + ["shop_entrance_down", "shop_basement"], ["idol_top", "idol"], ["udjattop", "udjatentrance"], ["machine_keyroom", "machine_rewardroom"], @@ -274,9 +276,8 @@ def get_template_draw_item(room_template, index): "pen_room", "ghistshop", "empress_grave", + "shop", "vault", - "shop_entrance_up", - "shop_entrance_down", "diceshop", "curioshop", "cavemanshop", From 88ee70f6fba6f5ebac06c983214c1b4fbe24a67e Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 12:45:52 -0700 Subject: [PATCH 25/61] Mark changes being made even if the room isn't selected. --- src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index e583d103..6b6d4ae9 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -601,7 +601,7 @@ def multiroom_editor_selected_tile(self, tile_name, image, is_primary): def multiroom_editor_modified_room(self, template_draw_item): if template_draw_item.room_chunk == self.current_selected_room: self.room_select(None) - self.changes_made() + self.changes_made() def save_requested(self): if self.save_needed: From f3ea4ce72e303a8b283098c9f9ab7db9627e7184 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 12:53:55 -0700 Subject: [PATCH 26/61] Fix hiding room lines. --- src/modlunky2/ui/levels/shared/level_canvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/shared/level_canvas.py b/src/modlunky2/ui/levels/shared/level_canvas.py index 6ce882a2..2ff247ef 100644 --- a/src/modlunky2/ui/levels/shared/level_canvas.py +++ b/src/modlunky2/ui/levels/shared/level_canvas.py @@ -194,7 +194,7 @@ def draw_grid(self, width=1): def draw_room_grid(self, width=1, special_room_sizes: GridRoom=None): def create_room_boundary_box(row, col, w, h): - self.create_rectangle( + return self.create_rectangle( col * 10 * self.zoom_level, row * 8 * self.zoom_level, (col + w) * 10 * self.zoom_level - 1 + (width - 1), From b769976f2895632f0c84cc564d1fbb59bb21cbfa Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 13:06:37 -0700 Subject: [PATCH 27/61] Choose non-ignore room templates. --- .../ui/levels/vanilla_levels/multi_room/room_map.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index c9b676e6..59a9e5df 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -1,5 +1,6 @@ import math +from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.vanilla_types import ( RoomInstance, @@ -44,9 +45,17 @@ def set_room(room_map, x, y, room): setroom_start = 0 def get_template_draw_item(room_template, index): - chunk_index = 0 + chunk_index = None if len(room_template.rooms) == 0: return None + for i, c in enumerate(room_template.rooms): + if TemplateSetting.IGNORE not in c.settings: + chunk_index = i + break + + if chunk_index is None: + return None + chunk = room_template.rooms[chunk_index] if chunk is None or len(chunk.front) == 0: return None From 6ad1e461bd3481f03099be10adac5e4734f74eea Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 14:17:46 -0700 Subject: [PATCH 28/61] Load a new chunk in multi-room editor if the visible chunk is deleted. --- .../multi_room/multi_room_editor_tab.py | 38 +++++++++++++- .../vanilla_levels/multi_room/room_map.py | 49 +++++++++---------- .../vanilla_levels/vanilla_level_editor.py | 1 + 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index f1df4578..3724475e 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -10,7 +10,7 @@ from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.multi_room.options_panel import OptionsPanel -from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap +from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap, get_template_draw_item from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( TemplateDrawItem, ) @@ -192,6 +192,42 @@ def add_tilecode(self, tile, percent, alt_tile): def delete_tilecode(self, tile_name, tile_code): self.on_delete_tilecode(tile_name, tile_code) + def room_was_deleted(self, template_index, chunk_index): + replaced = False + for row, template_row in enumerate(self.template_draw_map): + for col, template in enumerate(template_row): + if template is None: + continue + if template.template_index == template_index and template.room_index == chunk_index: + new_draw_item = get_template_draw_item(template.template, template_index) + template_row[col] = new_draw_item + replaced = True + # new_chunk_index = None + # if len(template.rooms) == 0: + # return None + # for i, c in enumerate(room_template.rooms): + # if TemplateSetting.IGNORE not in c.settings: + # chunk_index = i + # break + + # if chunk_index is None: + # return None + + # chunk = room_template.rooms[chunk_index] + # if chunk is None or len(chunk.front) == 0: + # return None + # return TemplateDrawItem( + # room_template, + # index, + # chunk, + # chunk_index, + # int(math.ceil(len(chunk.front[0]) / 10)), + # int(math.ceil(len(chunk.front) / 8)), + # ) + if replaced: + self.redraw() + + def canvas_click(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 # template_draw_item = self.template_draw_map[room_row][room_col] diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 59a9e5df..679fd23a 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -11,6 +11,30 @@ TemplateDrawItem, ) +def get_template_draw_item(room_template, index): + chunk_index = None + if len(room_template.rooms) == 0: + return None + for i, c in enumerate(room_template.rooms): + if TemplateSetting.IGNORE not in c.settings: + chunk_index = i + break + + if chunk_index is None: + return None + + chunk = room_template.rooms[chunk_index] + if chunk is None or len(chunk.front) == 0: + return None + return TemplateDrawItem( + room_template, + index, + chunk, + chunk_index, + int(math.ceil(len(chunk.front[0]) / 10)), + int(math.ceil(len(chunk.front) / 8)), + ) + def find_roommap(templates): setrooms = {} for room_template in templates: @@ -44,31 +68,6 @@ def set_room(room_map, x, y, room): room_map = [] setroom_start = 0 - def get_template_draw_item(room_template, index): - chunk_index = None - if len(room_template.rooms) == 0: - return None - for i, c in enumerate(room_template.rooms): - if TemplateSetting.IGNORE not in c.settings: - chunk_index = i - break - - if chunk_index is None: - return None - - chunk = room_template.rooms[chunk_index] - if chunk is None or len(chunk.front) == 0: - return None - return TemplateDrawItem( - room_template, - index, - chunk, - chunk_index, - int(math.ceil(len(chunk.front[0]) / 10)), - int(math.ceil(len(chunk.front) / 8)), - ) - - for _, setroomtype in setrooms.items(): for matchedtemplate in setroomtype: match = matchedtemplate.setroom diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 6b6d4ae9..9ae4e51b 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -1161,6 +1161,7 @@ def on_delete_room(self, parent_index, room_index): self.canvas.show_intro() del room_template.rooms[room_index] self.changes_made() + self.multi_room_editor_tab.room_was_deleted(parent_index, room_index) def on_copy_room(self, parent_index, room_index): room_template = self.template_list[parent_index] From cb327847944d632902265519013a0b22da17d878 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 17:12:49 -0700 Subject: [PATCH 29/61] Bye bye comments --- .../multi_room/multi_room_editor_tab.py | 24 +------------------ .../multi_room/options_panel.py | 4 ---- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 3724475e..3854b5ef 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -194,7 +194,7 @@ def delete_tilecode(self, tile_name, tile_code): def room_was_deleted(self, template_index, chunk_index): replaced = False - for row, template_row in enumerate(self.template_draw_map): + for _, template_row in enumerate(self.template_draw_map): for col, template in enumerate(template_row): if template is None: continue @@ -202,28 +202,6 @@ def room_was_deleted(self, template_index, chunk_index): new_draw_item = get_template_draw_item(template.template, template_index) template_row[col] = new_draw_item replaced = True - # new_chunk_index = None - # if len(template.rooms) == 0: - # return None - # for i, c in enumerate(room_template.rooms): - # if TemplateSetting.IGNORE not in c.settings: - # chunk_index = i - # break - - # if chunk_index is None: - # return None - - # chunk = room_template.rooms[chunk_index] - # if chunk is None or len(chunk.front) == 0: - # return None - # return TemplateDrawItem( - # room_template, - # index, - # chunk, - # chunk_index, - # int(math.ceil(len(chunk.front[0]) / 10)), - # int(math.ceil(len(chunk.front) / 8)), - # ) if replaced: self.redraw() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index e3a43e03..7af7de73 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -20,14 +20,10 @@ def __init__( self.on_update_hide_room_lines = on_update_hide_room_lines self.on_update_zoom_level = on_update_zoom_level - - # self.rowconfigure(2, minsize=20) - # self.rowconfigure(4, minsize=20) self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) self.columnconfigure(2, minsize=10) - # right_padding = 10 settings_row = 0 From 4341380e0882e5a5fdcc42de3bbdea292ba1b05d Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 19 Nov 2023 18:32:54 -0700 Subject: [PATCH 30/61] Display chunk map in options panel. --- .../multi_room/multi_room_editor_tab.py | 4 +- .../multi_room/options_panel.py | 121 ++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 3854b5ef..cac22a6e 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -151,6 +151,7 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.canvas.clear() self.show_intro() self.template_draw_map = find_roommap(room_templates) + self.options_panel.set_templates(self.template_draw_map) self.draw_canvas() def redraw(self): @@ -203,12 +204,12 @@ def room_was_deleted(self, template_index, chunk_index): template_row[col] = new_draw_item replaced = True if replaced: + self.options_panel.set_templates(self.template_draw_map) self.redraw() def canvas_click(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - # template_draw_item = self.template_draw_map[room_row][room_col] template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) if template_draw_item is None: @@ -243,7 +244,6 @@ def canvas_click(self, canvas_index, row, column, is_primary): def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - # template_draw_item = self.template_draw_map[room_row][room_col] template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) if template_draw_item is None: diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 7af7de73..c23e9d68 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -24,6 +24,8 @@ def __init__( self.columnconfigure(1, weight=1) self.columnconfigure(2, minsize=10) + self.templates = [] + settings_row = 0 @@ -95,5 +97,124 @@ def update_grid_size(_): grid_size_scale["command"] = update_grid_size self.grid_size_var = grid_size_var + settings_row += 1 + + self.room_type_frame = tk.Frame(self) + self.room_type_frame.grid(row=settings_row, column=1, sticky="news", padx=10, pady=10) + + self.room_view_size = 30 + self.room_view_padding = 5 + + for n in range(8): + # self.room_type_frame.columnconfigure(n * 2 + 2, minsize=10) + self.room_type_frame.columnconfigure(n * 2, minsize=self.room_view_size) + if n != 0: + self.room_type_frame.columnconfigure(n * 2 - 1, minsize=self.room_view_padding) + + self.room_buttons = [] + self.edge_frames = [] + + # s1 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) + # s1.grid(row=0, column=0, sticky="news") + # s2 = tk.Button(self.room_type_frame, bg="#3A403A", activebackground="#3A403A", relief=tk.GROOVE) + # s2.grid(row=2, column=0, sticky="news") + # s3 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) + # s3.grid(row=0, column=2, rowspan=3, columnspan=3, sticky="news") + # s4 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) + # s4.grid(row=0, column=6, rowspan=1, columnspan=3, sticky="news") + + def set_templates(self, templates): + if self.templates is not None: + for row_index in range(len(self.templates) + 1): + self.room_type_frame.rowconfigure(row_index * 2, minsize=0) + if row_index != 0: + self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=0) + + self.templates = templates + + if templates is not None: + for row_index in range(len(templates) + 1): + self.room_type_frame.rowconfigure(row_index * 2, minsize=self.room_view_size) + if row_index != 0: + self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=self.room_view_padding) + + for button in self.room_buttons: + button.grid_remove() + + for frame in self.edge_frames: + frame.grid_remove() + + self.room_buttons = [] + self.edge_frames = [] + + for row_index, template_row in enumerate(templates): + for col_index, template in enumerate(template_row): + new_button = None + if template is None: + overlapping_template, _, _ = self.template_item_at(templates, row_index, col_index) + if overlapping_template is None: + new_button = tk.Button(self.room_type_frame, bg="#3A403A", activebackground="#3A403A", relief=tk.GROOVE) + new_button.grid(row=row_index * 2, column=col_index * 2, sticky="news") + else: + new_button = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) + new_button.grid( + row=row_index * 2, + column=col_index * 2, + rowspan=template.height_in_rooms * 2 - 1, + columnspan=template.width_in_rooms * 2 - 1, + sticky="news", + ) + if new_button is not None: + self.room_buttons.append(new_button) + + if len(template_row) < 10: + edge_frame = tk.Frame(self.room_type_frame) + edge_frame.grid(row=row_index * 2, column=len(template_row) * 2, sticky="news") + edge_frame.columnconfigure(0, weight=1) + edge_frame.rowconfigure(0, weight=1) + + edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) + edge_button.grid(row=0, column=0, sticky="news") + edge_button.grid_remove() + + + edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) + edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + self.edge_frames.append(edge_frame) + + if len(templates) > 0: + row = len(templates) * 2 + for col in range(len(templates[0])): + edge_frame = tk.Frame(self.room_type_frame) + edge_frame.grid(row=row, column=col * 2, sticky="news") + edge_frame.columnconfigure(0, weight=1) + edge_frame.rowconfigure(0, weight=1) + + edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) + edge_button.grid(row=0, column=0, sticky="news") + edge_button.grid_remove() + + + edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) + edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + self.edge_frames.append(edge_frame) + + + + def update_zoom_level(self, zoom_level): self.grid_size_var.set(zoom_level) + + def template_item_at(self, templates, row, col): + for room_row_index, room_row in enumerate(templates): + if room_row_index > row: + return None, None, None + for room_column_index, template_draw_item in enumerate(room_row): + if room_column_index > col: + break + if template_draw_item is None: + continue + if room_row_index + template_draw_item.height_in_rooms - 1 >= row and room_column_index + template_draw_item.width_in_rooms - 1 >= col: + return template_draw_item, room_row_index, room_column_index + + return None, None, None \ No newline at end of file From e63f43f774e73b767a120db7e39393463fb4d724 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Mon, 11 Dec 2023 21:55:51 -0700 Subject: [PATCH 31/61] Add template select combobox when selecting a room in the map. --- .../multi_room/multi_room_editor_tab.py | 35 +++++- .../multi_room/options_panel.py | 116 ++++++++++++++---- 2 files changed, 127 insertions(+), 24 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index cac22a6e..fae19430 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +import math from PIL import Image, ImageTk import tkinter as tk from tkinter import ttk @@ -124,6 +125,7 @@ def toggle_panel_hidden(): self.canvas.hide_grid_lines, self.canvas.hide_room_lines, self.__update_zoom_internal, + self.change_template_at, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -151,7 +153,7 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.canvas.clear() self.show_intro() self.template_draw_map = find_roommap(room_templates) - self.options_panel.set_templates(self.template_draw_map) + self.options_panel.set_templates(self.template_draw_map, room_templates) self.draw_canvas() def redraw(self): @@ -173,6 +175,37 @@ def __set_zoom(self, zoom): self.tile_image_map = {} self.redraw() + def __get_template_draw_item(self, template, template_index): + chunk_index = None + if len(template.rooms) == 0: + return None + for i, c in enumerate(template.rooms): + if TemplateSetting.IGNORE not in c.settings: + chunk_index = i + break + + if chunk_index is None: + return None + + chunk = template.rooms[chunk_index] + if chunk is None or len(chunk.front) == 0: + return None + return TemplateDrawItem( + template, + template_index, + chunk, + chunk_index, + int(math.ceil(len(chunk.front[0]) / 10)), + int(math.ceil(len(chunk.front) / 8)), + ) + + def change_template_at(self, row, col, template, template_index): + template_draw_item = self.__get_template_draw_item(template, template_index) + if template_draw_item: + self.template_draw_map[row][col] = template_draw_item + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( tile_palette, diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index c23e9d68..e0eeee6c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -1,6 +1,52 @@ import tkinter as tk from tkinter import ttk +class RoomOptions(ttk.Frame): + def __init__( + self, + parent, + on_select_template, + *args, + **kwargs, + ): + super().__init__(parent, *args, **kwargs) + + setting_row = 0 + + self.on_select_template = on_select_template + + self.current_template_row = None + self.current_template_column = None + self.current_template_item = None + + self.columnconfigure(0, weight=1) + + template_label = tk.Label(self, text="Room Type:") + template_label.grid(row=setting_row, column=0, sticky="w") + + setting_row += 1 + + self.template_combobox = ttk.Combobox(self, height=25) + self.template_combobox.grid(row=setting_row, column=0, sticky="nsw") + self.template_combobox["state"] = "readonly" + self.template_combobox.bind("<>", lambda _: self.select_template()) + + def select_template(self): + template_index = self.template_combobox.current() + + self.on_select_template(template_index, self.current_template_row, self.current_template_column) + + def set_templates(self, templates): + self.template_combobox["values"] = [template.name for template in templates] + self.current_template_item = None + + def set_current_template(self, template, row, column): + self.current_template_item = template + self.current_template_row = row + self.current_template_column = column + if template: + self.template_combobox.set(template.template.name) + class OptionsPanel(ttk.Frame): def __init__( self, @@ -10,6 +56,7 @@ def __init__( on_update_hide_grid_lines, on_update_hide_room_lines, on_update_zoom_level, + on_change_template_at, *args, **kwargs ): @@ -19,13 +66,17 @@ def __init__( self.on_update_hide_grid_lines = on_update_hide_grid_lines self.on_update_hide_room_lines = on_update_hide_room_lines self.on_update_zoom_level = on_update_zoom_level + self.on_change_template_at = on_change_template_at self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) self.columnconfigure(2, minsize=10) + self.room_map = [] self.templates = [] + self.button_for_selected_room = None + settings_row = 0 @@ -106,7 +157,6 @@ def update_grid_size(_): self.room_view_padding = 5 for n in range(8): - # self.room_type_frame.columnconfigure(n * 2 + 2, minsize=10) self.room_type_frame.columnconfigure(n * 2, minsize=self.room_view_size) if n != 0: self.room_type_frame.columnconfigure(n * 2 - 1, minsize=self.room_view_padding) @@ -114,26 +164,30 @@ def update_grid_size(_): self.room_buttons = [] self.edge_frames = [] - # s1 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) - # s1.grid(row=0, column=0, sticky="news") - # s2 = tk.Button(self.room_type_frame, bg="#3A403A", activebackground="#3A403A", relief=tk.GROOVE) - # s2.grid(row=2, column=0, sticky="news") - # s3 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) - # s3.grid(row=0, column=2, rowspan=3, columnspan=3, sticky="news") - # s4 = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) - # s4.grid(row=0, column=6, rowspan=1, columnspan=3, sticky="news") + settings_row += 1 + + self.room_options = RoomOptions(self, self.update_room_map_template) + self.room_options.grid(row=settings_row, column=1, sticky="news") - def set_templates(self, templates): - if self.templates is not None: - for row_index in range(len(self.templates) + 1): + def update_room_map_template(self, template_index, row, column): + template = self.templates[template_index] + self.on_change_template_at(row, column, template, template_index) + + def set_templates(self, room_map, templates): + # self.room_options.grid_remove() + if self.room_map is not None: + for row_index in range(len(self.room_map) + 1): self.room_type_frame.rowconfigure(row_index * 2, minsize=0) if row_index != 0: self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=0) + self.room_map = room_map self.templates = templates - if templates is not None: - for row_index in range(len(templates) + 1): + self.room_options.set_templates(templates) + + if room_map is not None: + for row_index in range(len(room_map) + 1): self.room_type_frame.rowconfigure(row_index * 2, minsize=self.room_view_size) if row_index != 0: self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=self.room_view_padding) @@ -147,16 +201,24 @@ def set_templates(self, templates): self.room_buttons = [] self.edge_frames = [] - for row_index, template_row in enumerate(templates): + for row_index, template_row in enumerate(room_map): for col_index, template in enumerate(template_row): new_button = None if template is None: - overlapping_template, _, _ = self.template_item_at(templates, row_index, col_index) + overlapping_template, _, _ = self.template_item_at(room_map, row_index, col_index) if overlapping_template is None: new_button = tk.Button(self.room_type_frame, bg="#3A403A", activebackground="#3A403A", relief=tk.GROOVE) new_button.grid(row=row_index * 2, column=col_index * 2, sticky="news") else: - new_button = tk.Button(self.room_type_frame, bg="#30F030", activebackground="#30F030", relief=tk.GROOVE) + new_button = tk.Button( + self.room_type_frame, + bg="#30F030", + activebackground="#30F030", + relief=tk.GROOVE, + ) + new_button.configure( + command=lambda t=template, nb=new_button, r=row_index, c=col_index: self.select_template_item(t, nb, r, c) + ) new_button.grid( row=row_index * 2, column=col_index * 2, @@ -182,9 +244,9 @@ def set_templates(self, templates): edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) self.edge_frames.append(edge_frame) - if len(templates) > 0: - row = len(templates) * 2 - for col in range(len(templates[0])): + if len(room_map) > 0: + row = len(room_map) * 2 + for col in range(len(room_map[0])): edge_frame = tk.Frame(self.room_type_frame) edge_frame.grid(row=row, column=col * 2, sticky="news") edge_frame.columnconfigure(0, weight=1) @@ -199,14 +261,22 @@ def set_templates(self, templates): edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) self.edge_frames.append(edge_frame) + def reset_selected_button(self): + if self.button_for_selected_room is not None: + self.button_for_selected_room.configure(bg="#30F030", activebackground="#30F030") + self.button_for_selected_room = None - + def select_template_item(self, template_item, button, row, column): + self.reset_selected_button() + self.button_for_selected_room = button + button.configure(bg="#228B22", activebackground="#228B22") + self.room_options.set_current_template(template_item, row, column) def update_zoom_level(self, zoom_level): self.grid_size_var.set(zoom_level) - def template_item_at(self, templates, row, col): - for room_row_index, room_row in enumerate(templates): + def template_item_at(self, room_map, row, col): + for room_row_index, room_row in enumerate(room_map): if room_row_index > row: return None, None, None for room_column_index, template_draw_item in enumerate(room_row): From 93c932699e55fcc2906bc94247ccc6c9807faba7 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Mon, 11 Dec 2023 23:00:54 -0700 Subject: [PATCH 32/61] Draw on other rooms of same chunk. --- .../multi_room/multi_room_editor_tab.py | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index fae19430..6ba15aa4 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -175,17 +175,36 @@ def __set_zoom(self, zoom): self.tile_image_map = {} self.redraw() - def __get_template_draw_item(self, template, template_index): + def __get_template_draw_item(self, template, template_index, row, column): chunk_index = None if len(template.rooms) == 0: return None - for i, c in enumerate(template.rooms): - if TemplateSetting.IGNORE not in c.settings: - chunk_index = i - break + valid_rooms = [index for index, room in enumerate(template.rooms) if TemplateSetting.IGNORE not in room.settings] + + if row is not None and column is not None: + for i in valid_rooms: + room_used = False + for r, room_row in enumerate(self.template_draw_map): + for c, room in enumerate(room_row): + if room is None: + continue + if r == row and c == column: + continue + if room.template_index == template_index and room.room_index == i: + room_used = True + break + if room_used: + break + + if not room_used: + chunk_index = i + break if chunk_index is None: - return None + if len(valid_rooms) > 0: + chunk_index = valid_rooms[0] + else: + return None chunk = template.rooms[chunk_index] if chunk is None or len(chunk.front) == 0: @@ -200,7 +219,7 @@ def __get_template_draw_item(self, template, template_index): ) def change_template_at(self, row, col, template, template_index): - template_draw_item = self.__get_template_draw_item(template, template_index) + template_draw_item = self.__get_template_draw_item(template, template_index, row, col) if template_draw_item: self.template_draw_map[row][col] = template_draw_item self.options_panel.set_templates(self.template_draw_map, self.room_templates) @@ -266,14 +285,19 @@ def canvas_click(self, canvas_index, row, column, is_primary): layer[tile_row][tile_col] = tile_code self.on_modify_room(template_draw_item) - self.canvas.replace_tile_at( - canvas_index, - row, - column, - self.image_for_tile_code(tile_code), - x_offset, - y_offset, - ) + for r, room_rows in enumerate(self.template_draw_map): + for c, other_template_draw_item in enumerate(room_rows): + if other_template_draw_item is None: + continue + if template_draw_item.template_index == other_template_draw_item.template_index and template_draw_item.room_index == other_template_draw_item.room_index: + self.canvas.replace_tile_at( + canvas_index, + tile_row + r * 8, + tile_col + c * 10, + self.image_for_tile_code(tile_code), + x_offset, + y_offset, + ) def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 From 44c873055bf7351c325ac601f4861223ce774ca3 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Thu, 14 Dec 2023 23:42:01 -0700 Subject: [PATCH 33/61] Add warnings when new template will override another or expand too wide. --- .../multi_room/multi_room_editor_tab.py | 78 ++++++++++++++++++- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 6ba15aa4..ee2d7c27 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -20,6 +20,7 @@ RoomTemplate, MatchedSetroomTemplate, ) +from modlunky2.ui.widgets import PopupWindow class MultiRoomEditorTab(ttk.Frame): @@ -221,9 +222,80 @@ def __get_template_draw_item(self, template, template_index, row, column): def change_template_at(self, row, col, template, template_index): template_draw_item = self.__get_template_draw_item(template, template_index, row, col) if template_draw_item: - self.template_draw_map[row][col] = template_draw_item - self.options_panel.set_templates(self.template_draw_map, self.room_templates) - self.redraw() + if template_draw_item.width_in_rooms + col > 8: + # TODO: add error dialog. + win = PopupWindow("Cannot use this room template", self.modlunky_config) + lbl = ttk.Label(win, text="Using this template here will result in the map exceeding the maximum width.") + lbl.grid(row=0, column=0) + + ok_button = ttk.Button(win, text="OK", command=win.destroy) + ok_button.grid(row=1, column=0, pady=5, sticky="news") + return + + overlaps_room = False + for row_offset in range(template_draw_item.height_in_rooms): + for col_offset in range(template_draw_item.width_in_rooms): + if row_offset == 0 and col_offset == 0: + continue + template, overlapping_row, overlapping_column = self.template_item_at(row + row_offset, col + col_offset) + if template is not None and (overlapping_row != row or overlapping_column != col): + overlaps_room = True + + def update_template(): + self.template_draw_map[row][col] = template_draw_item + def expand_to_height_if_necessary(room_map, height): + if len(room_map) < height: + for _ in range(height - len(room_map)): + if len(room_map) == 0: + room_map.append([None]) + else: + room_map.append([None for _ in range(len(room_map[0]))]) + + def expand_to_width_if_necessary(room_map, width): + for row in room_map: + if len(row) < width: + for _ in range(width - len(row)): + row.append(None) + + expand_to_height_if_necessary(self.template_draw_map, row + template_draw_item.height_in_rooms) + expand_to_width_if_necessary(self.template_draw_map, col + template_draw_item.width_in_rooms) + for row_offset in range(template_draw_item.height_in_rooms): + for col_offset in range(template_draw_item.width_in_rooms): + if row_offset == 0 and col_offset == 0: + continue + self.template_draw_map[row + row_offset][col + col_offset] = None + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() + + + if overlaps_room: + win = PopupWindow("Warning", self.modlunky_config) + def update_then_destroy(): + update_template() + win.destroy() + + lbl = ttk.Label(win, text="Using this template here will remove some other templates.") + lbl.grid(row=0, column=0) + lbl2 = ttk.Label(win, text="Proceed anyway?") + lbl2.grid(row=1, column=0) + + separator = ttk.Separator(win) + separator.grid(row=2, column=0, columnspan=3, pady=5, sticky="nsew") + + buttons = ttk.Frame(win) + buttons.grid(row=3, column=0, columnspan=2, sticky="nsew") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + ok_button = ttk.Button(buttons, text="Proceed", command=update_then_destroy) + ok_button.grid(row=0, column=0, pady=5, sticky="nsew") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="nsew") + + else: + update_template() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( From 9033dd54858594206c701c0f08fa0296c38d70d7 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 00:00:21 -0700 Subject: [PATCH 34/61] Add a None option to remove the template from the map. --- .../multi_room/multi_room_editor_tab.py | 5 ++++ .../multi_room/options_panel.py | 23 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index ee2d7c27..80283c84 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -127,6 +127,7 @@ def toggle_panel_hidden(): self.canvas.hide_room_lines, self.__update_zoom_internal, self.change_template_at, + self.clear_template_at, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -296,6 +297,10 @@ def update_then_destroy(): else: update_template() + def clear_template_at(self, row, col): + self.template_draw_map[row][col] = None + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index e0eeee6c..2b5fd8da 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -6,6 +6,7 @@ def __init__( self, parent, on_select_template, + on_clear_template, *args, **kwargs, ): @@ -14,6 +15,7 @@ def __init__( setting_row = 0 self.on_select_template = on_select_template + self.on_clear_template = on_clear_template self.current_template_row = None self.current_template_column = None @@ -28,16 +30,26 @@ def __init__( self.template_combobox = ttk.Combobox(self, height=25) self.template_combobox.grid(row=setting_row, column=0, sticky="nsw") + self.template_combobox["values"] = ["None"] + self.template_combobox.set("None") self.template_combobox["state"] = "readonly" self.template_combobox.bind("<>", lambda _: self.select_template()) def select_template(self): template_index = self.template_combobox.current() - self.on_select_template(template_index, self.current_template_row, self.current_template_column) + if template_index == 0: + self.clear_templates() + self.on_clear_template(self.current_template_row, self.current_template_column) + else: + self.on_select_template(template_index - 1, self.current_template_row, self.current_template_column) + + def clear_templates(self): + self.template_combobox["values"] = ["None"] + self.template_combobox.set("None") def set_templates(self, templates): - self.template_combobox["values"] = [template.name for template in templates] + self.template_combobox["values"] = ["None"] + [template.name for template in templates] self.current_template_item = None def set_current_template(self, template, row, column): @@ -57,6 +69,7 @@ def __init__( on_update_hide_room_lines, on_update_zoom_level, on_change_template_at, + on_clear_template, *args, **kwargs ): @@ -67,6 +80,7 @@ def __init__( self.on_update_hide_room_lines = on_update_hide_room_lines self.on_update_zoom_level = on_update_zoom_level self.on_change_template_at = on_change_template_at + self.on_clear_template = on_clear_template self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) @@ -166,13 +180,16 @@ def update_grid_size(_): settings_row += 1 - self.room_options = RoomOptions(self, self.update_room_map_template) + self.room_options = RoomOptions(self, self.update_room_map_template, self.clear_template) self.room_options.grid(row=settings_row, column=1, sticky="news") def update_room_map_template(self, template_index, row, column): template = self.templates[template_index] self.on_change_template_at(row, column, template, template_index) + def clear_template(self, row, column): + self.on_clear_template(row, column) + def set_templates(self, room_map, templates): # self.room_options.grid_remove() if self.room_map is not None: From e8dab6a50d54414ceccafce87e9823ff2b52412c Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 00:06:58 -0700 Subject: [PATCH 35/61] Fix overwriting some rooms --- .../vanilla_levels/multi_room/multi_room_editor_tab.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 80283c84..cc53f453 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -243,7 +243,6 @@ def change_template_at(self, row, col, template, template_index): overlaps_room = True def update_template(): - self.template_draw_map[row][col] = template_draw_item def expand_to_height_if_necessary(room_map, height): if len(room_map) < height: for _ in range(height - len(room_map)): @@ -264,7 +263,9 @@ def expand_to_width_if_necessary(room_map, width): for col_offset in range(template_draw_item.width_in_rooms): if row_offset == 0 and col_offset == 0: continue - self.template_draw_map[row + row_offset][col + col_offset] = None + _, overlapping_row, overlapping_column = self.template_item_at(row + row_offset, col + col_offset) + self.template_draw_map[overlapping_row][overlapping_column] = None + self.template_draw_map[row][col] = template_draw_item self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() From c5fa2ae2825f48a67bd34f89695a6dca3068eb1a Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 00:38:14 -0700 Subject: [PATCH 36/61] Allow for creating rooms from empty start points. --- .../multi_room/multi_room_editor_tab.py | 4 +- .../multi_room/options_panel.py | 41 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index cc53f453..08394836 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -223,7 +223,7 @@ def __get_template_draw_item(self, template, template_index, row, column): def change_template_at(self, row, col, template, template_index): template_draw_item = self.__get_template_draw_item(template, template_index, row, col) if template_draw_item: - if template_draw_item.width_in_rooms + col > 8: + if template_draw_item.width_in_rooms + col > 10: # TODO: add error dialog. win = PopupWindow("Cannot use this room template", self.modlunky_config) lbl = ttk.Label(win, text="Using this template here will result in the map exceeding the maximum width.") @@ -264,6 +264,8 @@ def expand_to_width_if_necessary(room_map, width): if row_offset == 0 and col_offset == 0: continue _, overlapping_row, overlapping_column = self.template_item_at(row + row_offset, col + col_offset) + if overlapping_row is None or overlapping_column is None: + continue self.template_draw_map[overlapping_row][overlapping_column] = None self.template_draw_map[row][col] = template_draw_item self.options_panel.set_templates(self.template_draw_map, self.room_templates) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 2b5fd8da..5797f697 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -59,6 +59,11 @@ def set_current_template(self, template, row, column): if template: self.template_combobox.set(template.template.name) + def set_empty_cell(self, row, column): + self.current_template_row = row + self.current_template_column = column + self.template_combobox.set("None") + class OptionsPanel(ttk.Frame): def __init__( self, @@ -90,6 +95,7 @@ def __init__( self.templates = [] self.button_for_selected_room = None + self.button_for_selected_empty_room = None settings_row = 0 @@ -170,7 +176,7 @@ def update_grid_size(_): self.room_view_size = 30 self.room_view_padding = 5 - for n in range(8): + for n in range(10): self.room_type_frame.columnconfigure(n * 2, minsize=self.room_view_size) if n != 0: self.room_type_frame.columnconfigure(n * 2 - 1, minsize=self.room_view_padding) @@ -191,6 +197,8 @@ def clear_template(self, row, column): self.on_clear_template(row, column) def set_templates(self, room_map, templates): + self.button_for_selected_room = None + self.button_for_selected_empty_room = None # self.room_options.grid_remove() if self.room_map is not None: for row_index in range(len(self.room_map) + 1): @@ -224,8 +232,14 @@ def set_templates(self, room_map, templates): if template is None: overlapping_template, _, _ = self.template_item_at(room_map, row_index, col_index) if overlapping_template is None: - new_button = tk.Button(self.room_type_frame, bg="#3A403A", activebackground="#3A403A", relief=tk.GROOVE) + new_button = tk.Button(self.room_type_frame, bg="#5A605A", activebackground="#5A605A", relief=tk.GROOVE) + new_button.configure( + command=lambda nb=new_button, r=row_index, c=col_index: self.select_empty_cell(nb, r, c) + ) new_button.grid(row=row_index * 2, column=col_index * 2, sticky="news") + if row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column: + self.button_for_selected_empty_room = new_button + self.room_options.set_empty_cell(row_index, col_index) else: new_button = tk.Button( self.room_type_frame, @@ -243,6 +257,9 @@ def set_templates(self, room_map, templates): columnspan=template.width_in_rooms * 2 - 1, sticky="news", ) + if row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column: + self.button_for_selected_room = new_button + self.room_options.set_current_template(template, row_index, col_index) if new_button is not None: self.room_buttons.append(new_button) @@ -277,18 +294,36 @@ def set_templates(self, room_map, templates): edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) self.edge_frames.append(edge_frame) + self.highlight_selected_button() def reset_selected_button(self): if self.button_for_selected_room is not None: self.button_for_selected_room.configure(bg="#30F030", activebackground="#30F030") self.button_for_selected_room = None + if self.button_for_selected_empty_room is not None: + self.button_for_selected_empty_room.configure(bg="#5A605A", activebackground="#5A605A") + self.button_for_selected_empty_room = None + + def highlight_selected_button(self): + if self.button_for_selected_room is not None: + self.button_for_selected_room.configure(bg="#228B22", activebackground="#228B22") + self.button_for_selected_room = None + if self.button_for_selected_empty_room is not None: + self.button_for_selected_empty_room.configure(bg="#1A201A", activebackground="#1A201A") + self.button_for_selected_empty_room = None def select_template_item(self, template_item, button, row, column): self.reset_selected_button() self.button_for_selected_room = button - button.configure(bg="#228B22", activebackground="#228B22") + self.highlight_selected_button() self.room_options.set_current_template(template_item, row, column) + def select_empty_cell(self, button, row, column): + self.reset_selected_button() + self.button_for_selected_empty_room = button + self.highlight_selected_button() + self.room_options.set_empty_cell(row, column) + def update_zoom_level(self, zoom_level): self.grid_size_var.set(zoom_level) From 68b1bcdefb5367e11e3f78d93716037c0dd68f3c Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 00:57:51 -0700 Subject: [PATCH 37/61] Hook up add button. --- .../multi_room/multi_room_editor_tab.py | 8 +-- .../multi_room/options_panel.py | 57 ++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 08394836..5b75e01a 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -284,18 +284,18 @@ def update_then_destroy(): lbl2.grid(row=1, column=0) separator = ttk.Separator(win) - separator.grid(row=2, column=0, columnspan=3, pady=5, sticky="nsew") + separator.grid(row=2, column=0, columnspan=3, pady=5, sticky="news") buttons = ttk.Frame(win) - buttons.grid(row=3, column=0, columnspan=2, sticky="nsew") + buttons.grid(row=3, column=0, columnspan=2, sticky="news") buttons.columnconfigure(0, weight=1) buttons.columnconfigure(1, weight=1) ok_button = ttk.Button(buttons, text="Proceed", command=update_then_destroy) - ok_button.grid(row=0, column=0, pady=5, sticky="nsew") + ok_button.grid(row=0, column=0, pady=5, sticky="news") cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) - cancel_button.grid(row=0, column=1, pady=5, sticky="nsew") + cancel_button.grid(row=0, column=1, pady=5, sticky="news") else: update_template() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 5797f697..4a7283a7 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -1,6 +1,9 @@ import tkinter as tk from tkinter import ttk +from modlunky2.config import Config +from modlunky2.ui.widgets import PopupWindow + class RoomOptions(ttk.Frame): def __init__( self, @@ -68,7 +71,7 @@ class OptionsPanel(ttk.Frame): def __init__( self, parent, - modlunky_config, + modlunky_config: Config, zoom_level, on_update_hide_grid_lines, on_update_hide_room_lines, @@ -272,6 +275,9 @@ def set_templates(self, room_map, templates): edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) edge_button.grid(row=0, column=0, sticky="news") edge_button.grid_remove() + edge_button.configure( + command=lambda r=row_index, c=len(template_row): self.show_create_new_dialog(r, c) + ) edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) @@ -289,6 +295,9 @@ def set_templates(self, room_map, templates): edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) edge_button.grid(row=0, column=0, sticky="news") edge_button.grid_remove() + edge_button.configure( + command=lambda r=len(room_map), c=col: self.show_create_new_dialog(r, c) + ) edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) @@ -324,6 +333,52 @@ def select_empty_cell(self, button, row, column): self.highlight_selected_button() self.room_options.set_empty_cell(row, column) + def show_create_new_dialog(self, row, column): + win = PopupWindow("Add room", self.modlunky_config) + + lbl = ttk.Label(win, text="Select a template to add.") + lbl.grid(row=0, column=0) + + warning_label = tk.Label( + win, text="", foreground="red", wraplength=200, justify=tk.LEFT + ) + warning_label.grid(row=2, column=0, sticky="nw", pady=(10, 0)) + warning_label.grid_remove() + + separator = ttk.Separator(win) + separator.grid(row=3, column=0, columnspan=3, pady=5, sticky="news") + + buttons = ttk.Frame(win) + buttons.grid(row=4, column=0, columnspan=2, sticky="news") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + template_combobox = ttk.Combobox(win, height=25) + template_combobox.grid(row=1, column=0, sticky="nsw") + template_combobox["values"] = [template.name for template in self.templates] + # template_combobox.set("") + template_combobox["state"] = "readonly" + # template_combobox.bind("<>", lambda _: self.select_template()) + + def add_then_destroy(): + template_index = template_combobox.current() + print(template_index) + if template_index is None or template_index == -1: + warning_label["text"] = "Select a room template" + warning_label.grid() + return + + self.room_options.set_empty_cell(row, column) + self.update_room_map_template(template_index, row, column) + win.destroy() + + ok_button = ttk.Button(buttons, text="Add", command=add_then_destroy) + ok_button.grid(row=0, column=0, pady=5, sticky="news") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="news") + + def update_zoom_level(self, zoom_level): self.grid_size_var.set(zoom_level) From 5f8289a3dd7a2f369dab1c92ea8d02995f8c925c Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 01:19:35 -0700 Subject: [PATCH 38/61] Clear empty rows and columns when changing room size or clearing a room. --- .../multi_room/multi_room_editor_tab.py | 57 +++++++++++++++++++ .../multi_room/options_panel.py | 3 - 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 5b75e01a..8ad6028c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -267,7 +267,36 @@ def expand_to_width_if_necessary(room_map, width): if overlapping_row is None or overlapping_column is None: continue self.template_draw_map[overlapping_row][overlapping_column] = None + self.template_draw_map[row][col] = template_draw_item + while len(self.template_draw_map) > 0: + has_room = False + r = len(self.template_draw_map) - 1 + for c in range(len(self.template_draw_map[r])): + t, _, _ = self.template_item_at(r, c) + if t is not None: + has_room = True + break + if has_room: + break + + self.template_draw_map.pop() + + while len(self.template_draw_map) > 0 and len(self.template_draw_map[0]) > 0: + has_room = False + for r in range(len(self.template_draw_map)): + c = len(self.template_draw_map[r]) - 1 + t, _, _ = self.template_item_at(r, c) + if t is not None: + has_room = True + break + if has_room: + break + + for r in self.template_draw_map: + r.pop() + + self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() @@ -302,6 +331,34 @@ def update_then_destroy(): def clear_template_at(self, row, col): self.template_draw_map[row][col] = None + + while len(self.template_draw_map) > 0: + has_room = False + r = len(self.template_draw_map) - 1 + for c in range(len(self.template_draw_map[r])): + t, _, _ = self.template_item_at(r, c) + if t is not None: + has_room = True + break + if has_room: + break + + self.template_draw_map.pop() + + while len(self.template_draw_map) > 0 and len(self.template_draw_map[0]) > 0: + has_room = False + for r in range(len(self.template_draw_map)): + c = len(self.template_draw_map[r]) - 1 + t, _, _ = self.template_item_at(r, c) + if t is not None: + has_room = True + break + if has_room: + break + + for r in self.template_draw_map: + r.pop() + self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 4a7283a7..000c181c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -356,13 +356,10 @@ def show_create_new_dialog(self, row, column): template_combobox = ttk.Combobox(win, height=25) template_combobox.grid(row=1, column=0, sticky="nsw") template_combobox["values"] = [template.name for template in self.templates] - # template_combobox.set("") template_combobox["state"] = "readonly" - # template_combobox.bind("<>", lambda _: self.select_template()) def add_then_destroy(): template_index = template_combobox.current() - print(template_index) if template_index is None or template_index == -1: warning_label["text"] = "Select a room template" warning_label.grid() From 9fd69d0b321ebc795fc79318f3b6514ad1f5ef32 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 10:02:15 -0700 Subject: [PATCH 39/61] Remove trojan. --- .../ui/levels/shared/level_canvas.py | 11 +- .../levels/shared/multi_canvas_container.py | 2 +- .../multi_room/multi_room_editor_tab.py | 149 +++++++++++++----- .../multi_room/options_panel.py | 134 ++++++++++++---- .../vanilla_levels/multi_room/room_map.py | 20 ++- 5 files changed, 233 insertions(+), 83 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/level_canvas.py b/src/modlunky2/ui/levels/shared/level_canvas.py index 2ff247ef..bab88536 100644 --- a/src/modlunky2/ui/levels/shared/level_canvas.py +++ b/src/modlunky2/ui/levels/shared/level_canvas.py @@ -17,6 +17,7 @@ class GridRoom: width: int height: int + class LevelCanvas(tk.Canvas): def __init__( self, parent, textures_dir, zoom_level, on_click, on_pull_tile, *args, **kwargs @@ -167,7 +168,6 @@ def draw_background_over_room(self, theme, row, col): anchor="nw", ) - def draw_grid(self, width=1): self.grid_lines = [ self.create_line( @@ -192,7 +192,7 @@ def draw_grid(self, width=1): ] self.hide_grid_lines(self.grid_hidden) - def draw_room_grid(self, width=1, special_room_sizes: GridRoom=None): + def draw_room_grid(self, width=1, special_room_sizes: GridRoom = None): def create_room_boundary_box(row, col, w, h): return self.create_rectangle( col * 10 * self.zoom_level, @@ -202,14 +202,17 @@ def create_room_boundary_box(row, col, w, h): outline="#30F030", width=width, ) + if special_room_sizes is not None: self.room_lines = [ - create_room_boundary_box(r.row, r.column, r.width, r.height) for r in special_room_sizes + create_room_boundary_box(r.row, r.column, r.width, r.height) + for r in special_room_sizes ] else: self.room_lines = [ create_room_boundary_box(row, col, 1, 1) - for row in range(0, int(self.height / 8)) for col in range(0, int(self.width / 10)) + for row in range(0, int(self.height / 8)) + for col in range(0, int(self.width / 10)) ] self.hide_room_lines(self.rooms_hidden) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index b050ab4f..c74b225e 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -259,7 +259,7 @@ def draw_grid(self, width=None): for canvas in self.canvases: canvas.draw_grid(width) - def draw_room_grid(self, width=1, special_room_sizes: GridRoom=None): + def draw_room_grid(self, width=1, special_room_sizes: GridRoom = None): for canvas in self.canvases: canvas.draw_room_grid(width, special_room_sizes) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 8ad6028c..c17919c2 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -11,7 +11,10 @@ from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.multi_room.options_panel import OptionsPanel -from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import find_roommap, get_template_draw_item +from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import ( + find_roommap, + get_template_draw_item, +) from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( TemplateDrawItem, ) @@ -138,9 +141,11 @@ def image_for_tile_code(self, tile_code): if tile_name in self.tile_image_map: return self.tile_image_map[tile_name] - new_tile_image = ImageTk.PhotoImage(self.texture_fetcher.get_texture( - tile_name, self.lvl_biome, self.lvl, self.zoom_level - )) + new_tile_image = ImageTk.PhotoImage( + self.texture_fetcher.get_texture( + tile_name, self.lvl_biome, self.lvl, self.zoom_level + ) + ) self.tile_image_map[tile_name] = new_tile_image return new_tile_image @@ -181,7 +186,11 @@ def __get_template_draw_item(self, template, template_index, row, column): chunk_index = None if len(template.rooms) == 0: return None - valid_rooms = [index for index, room in enumerate(template.rooms) if TemplateSetting.IGNORE not in room.settings] + valid_rooms = [ + index + for index, room in enumerate(template.rooms) + if TemplateSetting.IGNORE not in room.settings + ] if row is not None and column is not None: for i in valid_rooms: @@ -192,7 +201,10 @@ def __get_template_draw_item(self, template, template_index, row, column): continue if r == row and c == column: continue - if room.template_index == template_index and room.room_index == i: + if ( + room.template_index == template_index + and room.room_index == i + ): room_used = True break if room_used: @@ -221,12 +233,17 @@ def __get_template_draw_item(self, template, template_index, row, column): ) def change_template_at(self, row, col, template, template_index): - template_draw_item = self.__get_template_draw_item(template, template_index, row, col) + template_draw_item = self.__get_template_draw_item( + template, template_index, row, col + ) if template_draw_item: if template_draw_item.width_in_rooms + col > 10: # TODO: add error dialog. win = PopupWindow("Cannot use this room template", self.modlunky_config) - lbl = ttk.Label(win, text="Using this template here will result in the map exceeding the maximum width.") + lbl = ttk.Label( + win, + text="Using this template here will result in the map exceeding the maximum width.", + ) lbl.grid(row=0, column=0) ok_button = ttk.Button(win, text="OK", command=win.destroy) @@ -238,8 +255,14 @@ def change_template_at(self, row, col, template, template_index): for col_offset in range(template_draw_item.width_in_rooms): if row_offset == 0 and col_offset == 0: continue - template, overlapping_row, overlapping_column = self.template_item_at(row + row_offset, col + col_offset) - if template is not None and (overlapping_row != row or overlapping_column != col): + ( + template, + overlapping_row, + overlapping_column, + ) = self.template_item_at(row + row_offset, col + col_offset) + if template is not None and ( + overlapping_row != row or overlapping_column != col + ): overlaps_room = True def update_template(): @@ -257,16 +280,24 @@ def expand_to_width_if_necessary(room_map, width): for _ in range(width - len(row)): row.append(None) - expand_to_height_if_necessary(self.template_draw_map, row + template_draw_item.height_in_rooms) - expand_to_width_if_necessary(self.template_draw_map, col + template_draw_item.width_in_rooms) + expand_to_height_if_necessary( + self.template_draw_map, row + template_draw_item.height_in_rooms + ) + expand_to_width_if_necessary( + self.template_draw_map, col + template_draw_item.width_in_rooms + ) for row_offset in range(template_draw_item.height_in_rooms): for col_offset in range(template_draw_item.width_in_rooms): if row_offset == 0 and col_offset == 0: continue - _, overlapping_row, overlapping_column = self.template_item_at(row + row_offset, col + col_offset) + _, overlapping_row, overlapping_column = self.template_item_at( + row + row_offset, col + col_offset + ) if overlapping_row is None or overlapping_column is None: continue - self.template_draw_map[overlapping_row][overlapping_column] = None + self.template_draw_map[overlapping_row][ + overlapping_column + ] = None self.template_draw_map[row][col] = template_draw_item while len(self.template_draw_map) > 0: @@ -282,7 +313,10 @@ def expand_to_width_if_necessary(room_map, width): self.template_draw_map.pop() - while len(self.template_draw_map) > 0 and len(self.template_draw_map[0]) > 0: + while ( + len(self.template_draw_map) > 0 + and len(self.template_draw_map[0]) > 0 + ): has_room = False for r in range(len(self.template_draw_map)): c = len(self.template_draw_map[r]) - 1 @@ -296,18 +330,22 @@ def expand_to_width_if_necessary(room_map, width): for r in self.template_draw_map: r.pop() - - self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.options_panel.set_templates( + self.template_draw_map, self.room_templates + ) self.redraw() - if overlaps_room: win = PopupWindow("Warning", self.modlunky_config) + def update_then_destroy(): update_template() win.destroy() - lbl = ttk.Label(win, text="Using this template here will remove some other templates.") + lbl = ttk.Label( + win, + text="Using this template here will remove some other templates.", + ) lbl.grid(row=0, column=0) lbl2 = ttk.Label(win, text="Proceed anyway?") lbl2.grid(row=1, column=0) @@ -320,7 +358,9 @@ def update_then_destroy(): buttons.columnconfigure(0, weight=1) buttons.columnconfigure(1, weight=1) - ok_button = ttk.Button(buttons, text="Proceed", command=update_then_destroy) + ok_button = ttk.Button( + buttons, text="Proceed", command=update_then_destroy + ) ok_button.grid(row=0, column=0, pady=5, sticky="news") cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) @@ -388,18 +428,24 @@ def room_was_deleted(self, template_index, chunk_index): for col, template in enumerate(template_row): if template is None: continue - if template.template_index == template_index and template.room_index == chunk_index: - new_draw_item = get_template_draw_item(template.template, template_index) + if ( + template.template_index == template_index + and template.room_index == chunk_index + ): + new_draw_item = get_template_draw_item( + template.template, template_index + ) template_row[col] = new_draw_item replaced = True if replaced: self.options_panel.set_templates(self.template_draw_map) self.redraw() - def canvas_click(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) + template_draw_item, room_row, room_col = self.template_item_at( + room_row, room_col + ) if template_draw_item is None: # Do not draw on empty room. @@ -426,7 +472,12 @@ def canvas_click(self, canvas_index, row, column, is_primary): for c, other_template_draw_item in enumerate(room_rows): if other_template_draw_item is None: continue - if template_draw_item.template_index == other_template_draw_item.template_index and template_draw_item.room_index == other_template_draw_item.room_index: + if ( + template_draw_item.template_index + == other_template_draw_item.template_index + and template_draw_item.room_index + == other_template_draw_item.room_index + ): self.canvas.replace_tile_at( canvas_index, tile_row + r * 8, @@ -438,7 +489,9 @@ def canvas_click(self, canvas_index, row, column, is_primary): def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 - template_draw_item, room_row, room_col = self.template_item_at(room_row, room_col) + template_draw_item, room_row, room_col = self.template_item_at( + room_row, room_col + ) if template_draw_item is None: # Do not attempt to pull tile from empty room. @@ -456,8 +509,6 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): if TemplateSetting.ONLYFLIP in chunk.settings: tile_col = 9 - tile_col - - tile_code = layer[tile_row][tile_col] tile = self.tile_palette_map[tile_code] @@ -469,7 +520,7 @@ def offset_for_tile(self, tile_name, tile_code, tile_size): # tile_ref = self.tile_palette_map[tile_code] img = self.image_for_tile_code(tile_code) # if tile_ref: - # img = tile_ref[1] + # img = tile_ref[1] if img: return self.texture_fetcher.adjust_texture_xy( img.width(), img.height(), tile_name, tile_size @@ -505,12 +556,14 @@ def draw_canvas(self): for room_column_index, template_draw_item in enumerate(room_row): if template_draw_item is None: continue - grid_sizes.append(GridRoom( - room_row_index, - room_column_index, - template_draw_item.width_in_rooms, - template_draw_item.height_in_rooms, - )) + grid_sizes.append( + GridRoom( + room_row_index, + room_column_index, + template_draw_item.width_in_rooms, + template_draw_item.height_in_rooms, + ) + ) self.canvas.draw_room_grid(2, grid_sizes) @@ -558,12 +611,23 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): else: for r in range(template_draw_item.height_in_rooms): for c in range(template_draw_item.width_in_rooms): - self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index + r, room_column_index + c) + self.canvas.draw_background_over_room( + 1, + self.lvl_biome, + room_row_index + r, + room_column_index + c, + ) else: - template, _, _ = self.template_item_at(room_row_index, room_column_index) + template, _, _ = self.template_item_at( + room_row_index, room_column_index + ) if template is None: - self.canvas.draw_background_over_room(0, self.lvl_biome, room_row_index, room_column_index) - self.canvas.draw_background_over_room(1, self.lvl_biome, room_row_index, room_column_index) + self.canvas.draw_background_over_room( + 0, self.lvl_biome, room_row_index, room_column_index + ) + self.canvas.draw_background_over_room( + 1, self.lvl_biome, room_row_index, room_column_index + ) def template_item_at(self, row, col): for room_row_index, room_row in enumerate(self.template_draw_map): @@ -574,7 +638,10 @@ def template_item_at(self, row, col): break if template_draw_item is None: continue - if room_row_index + template_draw_item.height_in_rooms - 1 >= row and room_column_index + template_draw_item.width_in_rooms - 1 >= col: + if ( + room_row_index + template_draw_item.height_in_rooms - 1 >= row + and room_column_index + template_draw_item.width_in_rooms - 1 >= col + ): return template_draw_item, room_row_index, room_column_index - return None, None, None \ No newline at end of file + return None, None, None diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 000c181c..84596a02 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -4,6 +4,7 @@ from modlunky2.config import Config from modlunky2.ui.widgets import PopupWindow + class RoomOptions(ttk.Frame): def __init__( self, @@ -36,23 +37,33 @@ def __init__( self.template_combobox["values"] = ["None"] self.template_combobox.set("None") self.template_combobox["state"] = "readonly" - self.template_combobox.bind("<>", lambda _: self.select_template()) + self.template_combobox.bind( + "<>", lambda _: self.select_template() + ) def select_template(self): template_index = self.template_combobox.current() if template_index == 0: self.clear_templates() - self.on_clear_template(self.current_template_row, self.current_template_column) + self.on_clear_template( + self.current_template_row, self.current_template_column + ) else: - self.on_select_template(template_index - 1, self.current_template_row, self.current_template_column) + self.on_select_template( + template_index - 1, + self.current_template_row, + self.current_template_column, + ) def clear_templates(self): self.template_combobox["values"] = ["None"] self.template_combobox.set("None") def set_templates(self, templates): - self.template_combobox["values"] = ["None"] + [template.name for template in templates] + self.template_combobox["values"] = ["None"] + [ + template.name for template in templates + ] self.current_template_item = None def set_current_template(self, template, row, column): @@ -67,6 +78,7 @@ def set_empty_cell(self, row, column): self.current_template_column = column self.template_combobox.set("None") + class OptionsPanel(ttk.Frame): def __init__( self, @@ -79,7 +91,7 @@ def __init__( on_change_template_at, on_clear_template, *args, - **kwargs + **kwargs, ): super().__init__(parent, *args, **kwargs) @@ -102,7 +114,6 @@ def __init__( settings_row = 0 - # Checkbox to toggle the visibility of the grid lines. hide_grid_var = tk.IntVar() hide_grid_var.set(False) @@ -174,7 +185,9 @@ def update_grid_size(_): settings_row += 1 self.room_type_frame = tk.Frame(self) - self.room_type_frame.grid(row=settings_row, column=1, sticky="news", padx=10, pady=10) + self.room_type_frame.grid( + row=settings_row, column=1, sticky="news", padx=10, pady=10 + ) self.room_view_size = 30 self.room_view_padding = 5 @@ -182,14 +195,18 @@ def update_grid_size(_): for n in range(10): self.room_type_frame.columnconfigure(n * 2, minsize=self.room_view_size) if n != 0: - self.room_type_frame.columnconfigure(n * 2 - 1, minsize=self.room_view_padding) + self.room_type_frame.columnconfigure( + n * 2 - 1, minsize=self.room_view_padding + ) self.room_buttons = [] self.edge_frames = [] settings_row += 1 - self.room_options = RoomOptions(self, self.update_room_map_template, self.clear_template) + self.room_options = RoomOptions( + self, self.update_room_map_template, self.clear_template + ) self.room_options.grid(row=settings_row, column=1, sticky="news") def update_room_map_template(self, template_index, row, column): @@ -216,9 +233,13 @@ def set_templates(self, room_map, templates): if room_map is not None: for row_index in range(len(room_map) + 1): - self.room_type_frame.rowconfigure(row_index * 2, minsize=self.room_view_size) + self.room_type_frame.rowconfigure( + row_index * 2, minsize=self.room_view_size + ) if row_index != 0: - self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=self.room_view_padding) + self.room_type_frame.rowconfigure( + row_index * 2 - 1, minsize=self.room_view_padding + ) for button in self.room_buttons: button.grid_remove() @@ -233,14 +254,28 @@ def set_templates(self, room_map, templates): for col_index, template in enumerate(template_row): new_button = None if template is None: - overlapping_template, _, _ = self.template_item_at(room_map, row_index, col_index) + overlapping_template, _, _ = self.template_item_at( + room_map, row_index, col_index + ) if overlapping_template is None: - new_button = tk.Button(self.room_type_frame, bg="#5A605A", activebackground="#5A605A", relief=tk.GROOVE) + new_button = tk.Button( + self.room_type_frame, + bg="#5A605A", + activebackground="#5A605A", + relief=tk.GROOVE, + ) new_button.configure( - command=lambda nb=new_button, r=row_index, c=col_index: self.select_empty_cell(nb, r, c) + command=lambda nb=new_button, r=row_index, c=col_index: self.select_empty_cell( + nb, r, c + ) + ) + new_button.grid( + row=row_index * 2, column=col_index * 2, sticky="news" ) - new_button.grid(row=row_index * 2, column=col_index * 2, sticky="news") - if row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column: + if ( + row_index == self.room_options.current_template_row + and col_index == self.room_options.current_template_column + ): self.button_for_selected_empty_room = new_button self.room_options.set_empty_cell(row_index, col_index) else: @@ -251,7 +286,9 @@ def set_templates(self, room_map, templates): relief=tk.GROOVE, ) new_button.configure( - command=lambda t=template, nb=new_button, r=row_index, c=col_index: self.select_template_item(t, nb, r, c) + command=lambda t=template, nb=new_button, r=row_index, c=col_index: self.select_template_item( + t, nb, r, c + ) ) new_button.grid( row=row_index * 2, @@ -260,26 +297,40 @@ def set_templates(self, room_map, templates): columnspan=template.width_in_rooms * 2 - 1, sticky="news", ) - if row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column: + if ( + row_index == self.room_options.current_template_row + and col_index == self.room_options.current_template_column + ): self.button_for_selected_room = new_button - self.room_options.set_current_template(template, row_index, col_index) + self.room_options.set_current_template( + template, row_index, col_index + ) if new_button is not None: self.room_buttons.append(new_button) if len(template_row) < 10: edge_frame = tk.Frame(self.room_type_frame) - edge_frame.grid(row=row_index * 2, column=len(template_row) * 2, sticky="news") + edge_frame.grid( + row=row_index * 2, column=len(template_row) * 2, sticky="news" + ) edge_frame.columnconfigure(0, weight=1) edge_frame.rowconfigure(0, weight=1) - edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) + edge_button = tk.Button( + edge_frame, + text="+", + bg="#A0C0A6", + activebackground="#A0C0A6", + relief=tk.GROOVE, + ) edge_button.grid(row=0, column=0, sticky="news") edge_button.grid_remove() edge_button.configure( - command=lambda r=row_index, c=len(template_row): self.show_create_new_dialog(r, c) + command=lambda r=row_index, c=len( + template_row + ): self.show_create_new_dialog(r, c) ) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) self.edge_frames.append(edge_frame) @@ -292,14 +343,21 @@ def set_templates(self, room_map, templates): edge_frame.columnconfigure(0, weight=1) edge_frame.rowconfigure(0, weight=1) - edge_button = tk.Button(edge_frame, text="+", bg="#A0C0A6", activebackground="#A0C0A6", relief=tk.GROOVE) + edge_button = tk.Button( + edge_frame, + text="+", + bg="#A0C0A6", + activebackground="#A0C0A6", + relief=tk.GROOVE, + ) edge_button.grid(row=0, column=0, sticky="news") edge_button.grid_remove() edge_button.configure( - command=lambda r=len(room_map), c=col: self.show_create_new_dialog(r, c) + command=lambda r=len(room_map), c=col: self.show_create_new_dialog( + r, c + ) ) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) self.edge_frames.append(edge_frame) @@ -307,18 +365,26 @@ def set_templates(self, room_map, templates): def reset_selected_button(self): if self.button_for_selected_room is not None: - self.button_for_selected_room.configure(bg="#30F030", activebackground="#30F030") + self.button_for_selected_room.configure( + bg="#30F030", activebackground="#30F030" + ) self.button_for_selected_room = None if self.button_for_selected_empty_room is not None: - self.button_for_selected_empty_room.configure(bg="#5A605A", activebackground="#5A605A") + self.button_for_selected_empty_room.configure( + bg="#5A605A", activebackground="#5A605A" + ) self.button_for_selected_empty_room = None def highlight_selected_button(self): if self.button_for_selected_room is not None: - self.button_for_selected_room.configure(bg="#228B22", activebackground="#228B22") + self.button_for_selected_room.configure( + bg="#228B22", activebackground="#228B22" + ) self.button_for_selected_room = None if self.button_for_selected_empty_room is not None: - self.button_for_selected_empty_room.configure(bg="#1A201A", activebackground="#1A201A") + self.button_for_selected_empty_room.configure( + bg="#1A201A", activebackground="#1A201A" + ) self.button_for_selected_empty_room = None def select_template_item(self, template_item, button, row, column): @@ -375,7 +441,6 @@ def add_then_destroy(): cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) cancel_button.grid(row=0, column=1, pady=5, sticky="news") - def update_zoom_level(self, zoom_level): self.grid_size_var.set(zoom_level) @@ -388,7 +453,10 @@ def template_item_at(self, room_map, row, col): break if template_draw_item is None: continue - if room_row_index + template_draw_item.height_in_rooms - 1 >= row and room_column_index + template_draw_item.width_in_rooms - 1 >= col: + if ( + room_row_index + template_draw_item.height_in_rooms - 1 >= row + and room_column_index + template_draw_item.width_in_rooms - 1 >= col + ): return template_draw_item, room_row_index, room_column_index - return None, None, None \ No newline at end of file + return None, None, None diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 679fd23a..836e6cfe 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -11,6 +11,7 @@ TemplateDrawItem, ) + def get_template_draw_item(room_template, index): chunk_index = None if len(room_template.rooms) == 0: @@ -35,6 +36,7 @@ def get_template_draw_item(room_template, index): int(math.ceil(len(chunk.front) / 8)), ) + def find_roommap(templates): setrooms = {} for room_template in templates: @@ -73,7 +75,9 @@ def set_room(room_map, x, y, room): match = matchedtemplate.setroom x, y = match.coords.x, match.coords.y - template_item = get_template_draw_item(matchedtemplate.template, templates.index(matchedtemplate.template)) + template_item = get_template_draw_item( + matchedtemplate.template, templates.index(matchedtemplate.template) + ) if template_item: set_room(room_map, x, setroom_start + y, template_item) @@ -180,10 +184,18 @@ def set_room(room_map, x, y, room): if challenge_special: if bottomc is not None and bottomr is not None: - set_room(room_map, bottomc < len(room_map[0]) and bottomc + 1 or bottomc - 1, bottomr, challenge_special) + set_room( + room_map, + bottomc < len(room_map[0]) and bottomc + 1 or bottomc - 1, + bottomr, + challenge_special, + ) elif entrancer is not None and entrancec is not None: cr, cc = entrancer + 1, entrancec - if entrancec < len(room_map[entrancer]) and room_map[entrancer][entrancec + 1] is None: + if ( + entrancec < len(room_map[entrancer]) + and room_map[entrancer][entrancec + 1] is None + ): cr, cc = entrancer, entrancec + 1 elif entrancec > 0 and room_map[entrancer][entrancec - 1] is None: cr, cc = entrancer, entrancec - 1 @@ -309,7 +321,7 @@ def set_room(room_map, x, y, room): room = template_map.get(room_name) added_room = False if room: - for row in range(more_rooms_start, more_rooms_bottom+1): + for row in range(more_rooms_start, more_rooms_bottom + 1): if added_room: break if len(room_map) <= row: From 6d10fdcdea450076cbec83c1ae615eb4dbdbd3bb Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 10:12:55 -0700 Subject: [PATCH 40/61] Hide the room options when a room is not selected. --- .../multi_room/multi_room_editor_tab.py | 1 + .../multi_room/options_panel.py | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index c17919c2..c36e9007 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -160,6 +160,7 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.canvas.clear() self.show_intro() self.template_draw_map = find_roommap(room_templates) + self.options_panel.reset() self.options_panel.set_templates(self.template_draw_map, room_templates) self.draw_canvas() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 84596a02..912e43a6 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -41,6 +41,13 @@ def __init__( "<>", lambda _: self.select_template() ) + def reset(self): + self.current_template_row = None + self.current_template_column = None + self.current_template_item = None + self.template_combobox["values"] = ["None"] + self.template_combobox.set("None") + def select_template(self): template_index = self.template_combobox.current() @@ -208,6 +215,7 @@ def update_grid_size(_): self, self.update_room_map_template, self.clear_template ) self.room_options.grid(row=settings_row, column=1, sticky="news") + self.room_options.grid_remove() def update_room_map_template(self, template_index, row, column): template = self.templates[template_index] @@ -216,9 +224,17 @@ def update_room_map_template(self, template_index, row, column): def clear_template(self, row, column): self.on_clear_template(row, column) + def reset(self): + print("reset") + self.button_for_selected_room = None + self.button_for_selected_empty_room = None + self.room_options.grid_remove() + self.room_options.reset() + def set_templates(self, room_map, templates): self.button_for_selected_room = None self.button_for_selected_empty_room = None + self.room_options.grid_remove() # self.room_options.grid_remove() if self.room_map is not None: for row_index in range(len(self.room_map) + 1): @@ -380,24 +396,26 @@ def highlight_selected_button(self): self.button_for_selected_room.configure( bg="#228B22", activebackground="#228B22" ) - self.button_for_selected_room = None + self.room_options.grid() if self.button_for_selected_empty_room is not None: self.button_for_selected_empty_room.configure( bg="#1A201A", activebackground="#1A201A" ) - self.button_for_selected_empty_room = None + self.room_options.grid() def select_template_item(self, template_item, button, row, column): self.reset_selected_button() self.button_for_selected_room = button self.highlight_selected_button() self.room_options.set_current_template(template_item, row, column) + self.room_options.grid() def select_empty_cell(self, button, row, column): self.reset_selected_button() self.button_for_selected_empty_room = button self.highlight_selected_button() self.room_options.set_empty_cell(row, column) + self.room_options.grid() def show_create_new_dialog(self, row, column): win = PopupWindow("Add room", self.modlunky_config) From 01b2d9a440d75eb4d6c6e9280a9152f5aec82770 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 10:15:01 -0700 Subject: [PATCH 41/61] Remove log --- .../ui/levels/vanilla_levels/multi_room/options_panel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 912e43a6..c14813ae 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -225,7 +225,6 @@ def clear_template(self, row, column): self.on_clear_template(row, column) def reset(self): - print("reset") self.button_for_selected_room = None self.button_for_selected_empty_room = None self.room_options.grid_remove() From 0d67a39cfe7c8d966eaf5d5a79df9f119851654a Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 21:06:53 -0700 Subject: [PATCH 42/61] Room selecting. --- .../multi_room/multi_room_editor_tab.py | 13 ++++++ .../multi_room/options_panel.py | 44 ++++++++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index c36e9007..0c07434f 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -131,6 +131,7 @@ def toggle_panel_hidden(): self.__update_zoom_internal, self.change_template_at, self.clear_template_at, + self.change_room_at, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -403,6 +404,18 @@ def clear_template_at(self, row, col): self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() + def change_room_at(self, room_index, row, col): + template_item = self.template_draw_map[row][col] + + if template_item is None: + return + + template_item.room_index = room_index + template_item.room_chunk = template_item.template.rooms[room_index] + + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( tile_palette, diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index c14813ae..4508e10f 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -11,6 +11,7 @@ def __init__( parent, on_select_template, on_clear_template, + on_select_room, *args, **kwargs, ): @@ -20,6 +21,7 @@ def __init__( self.on_select_template = on_select_template self.on_clear_template = on_clear_template + self.on_select_room = on_select_room self.current_template_row = None self.current_template_column = None @@ -37,16 +39,29 @@ def __init__( self.template_combobox["values"] = ["None"] self.template_combobox.set("None") self.template_combobox["state"] = "readonly" - self.template_combobox.bind( - "<>", lambda _: self.select_template() - ) + self.template_combobox.bind("<>", lambda _: self.select_template()) + + setting_row += 1 + + self.template_container = tk.Frame(self) + self.template_container.grid(row=setting_row, column=0, sticky="news") + + room_label = tk.Label(self.template_container, text="Room:") + room_label.grid(row=0, column=0, sticky="w") + + self.room_combobox = ttk.Combobox(self.template_container, height=25) + self.room_combobox.grid(row=1, column=0, sticky="nsw") + self.room_combobox["values"] = [] + self.room_combobox.set("") + self.room_combobox["state"] = "readonly" + self.room_combobox.bind("<>", lambda _: self.select_room()) def reset(self): self.current_template_row = None self.current_template_column = None self.current_template_item = None - self.template_combobox["values"] = ["None"] - self.template_combobox.set("None") + self.template_container.grid_remove() + self.clear_templates() def select_template(self): template_index = self.template_combobox.current() @@ -63,9 +78,15 @@ def select_template(self): self.current_template_column, ) + def select_room(self): + room_index = self.room_combobox.current() + self.on_select_room(room_index, self.current_template_row, self.current_template_column) + def clear_templates(self): self.template_combobox["values"] = ["None"] self.template_combobox.set("None") + self.room_combobox["values"] = [] + self.room_combobox.set("") def set_templates(self, templates): self.template_combobox["values"] = ["None"] + [ @@ -79,11 +100,20 @@ def set_current_template(self, template, row, column): self.current_template_column = column if template: self.template_combobox.set(template.template.name) + self.room_combobox["values"] = [ + room.name or "room " + (index + 1) for index, room in enumerate(template.template.rooms) + ] + self.room_combobox.set(template.room_chunk.name or "room " + (template.room_index + 1)) + self.room_combobox.current(template.room_index) + self.template_container.grid() + else: + self.set_empty_cell(row, column) def set_empty_cell(self, row, column): self.current_template_row = row self.current_template_column = column self.template_combobox.set("None") + self.template_container.grid_remove() class OptionsPanel(ttk.Frame): @@ -97,6 +127,7 @@ def __init__( on_update_zoom_level, on_change_template_at, on_clear_template, + on_select_room, *args, **kwargs, ): @@ -108,6 +139,7 @@ def __init__( self.on_update_zoom_level = on_update_zoom_level self.on_change_template_at = on_change_template_at self.on_clear_template = on_clear_template + self.on_select_room = on_select_room self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) @@ -212,7 +244,7 @@ def update_grid_size(_): settings_row += 1 self.room_options = RoomOptions( - self, self.update_room_map_template, self.clear_template + self, self.update_room_map_template, self.clear_template, self.on_select_room ) self.room_options.grid(row=settings_row, column=1, sticky="news") self.room_options.grid_remove() From 0c54d7234970d4ad4618627b12a02ff4dc52be38 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 21:47:52 -0700 Subject: [PATCH 43/61] Add room settings. --- .../multi_room/multi_room_editor_tab.py | 20 ++ .../multi_room/options_panel.py | 203 +++++++++++++++++- .../vanilla_levels/vanilla_level_editor.py | 1 + 3 files changed, 223 insertions(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 0c07434f..19471d7c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -132,6 +132,7 @@ def toggle_panel_hidden(): self.change_template_at, self.clear_template_at, self.change_room_at, + self.room_setting_change_at, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -170,6 +171,9 @@ def redraw(self): self.show_intro() self.draw_canvas() + def update_templates(self): + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + def update_zoom_level(self, zoom): self.options_panel.update_zoom_level(zoom) self.__set_zoom(zoom) @@ -416,6 +420,22 @@ def change_room_at(self, room_index, row, col): self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() + def room_setting_change_at(self, setting, value, row, col): + template_item = self.template_draw_map[row][col] + + if template_item is None: + return + + room = template_item.room_chunk + if value and not setting in room.settings: + room.settings.append(setting) + elif not value and setting in room.settings: + room.settings.remove(setting) + + self.on_modify_room(template_item) + if setting == TemplateSetting.DUAL or setting == TemplateSetting.ONLYFLIP: + self.redraw() + def populate_tilecode_palette(self, tile_palette, suggestions): self.palette_panel.update_with_palette( tile_palette, diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 4508e10f..1cd0c123 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -2,6 +2,7 @@ from tkinter import ttk from modlunky2.config import Config +from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.widgets import PopupWindow @@ -12,6 +13,7 @@ def __init__( on_select_template, on_clear_template, on_select_room, + on_flip_setting, *args, **kwargs, ): @@ -22,6 +24,7 @@ def __init__( self.on_select_template = on_select_template self.on_clear_template = on_clear_template self.on_select_room = on_select_room + self.on_flip_setting = on_flip_setting self.current_template_row = None self.current_template_column = None @@ -56,6 +59,112 @@ def __init__( self.room_combobox["state"] = "readonly" self.room_combobox.bind("<>", lambda _: self.select_room()) + self.room_settings_container = tk.Frame(self.template_container) + self.room_settings_container.grid(row=2, column=0, sticky="news") + + self.var_ignore = tk.IntVar() + self.var_flip = tk.IntVar() + self.var_only_flip = tk.IntVar() + self.var_dual = tk.IntVar() + self.var_rare = tk.IntVar() + self.var_hard = tk.IntVar() + self.var_liquid = tk.IntVar() + self.var_purge = tk.IntVar() + self.checkbox_ignore = ttk.Checkbutton( + self.room_settings_container, + text="Ignore", + var=self.var_ignore, + onvalue=1, + offvalue=0, + command=self.on_flip_ignore, + ) + self.checkbox_flip = ttk.Checkbutton( + self.room_settings_container, + text="Flip", + var=self.var_flip, + onvalue=1, + offvalue=0, + command=self.on_flip_flip, + ) + self.checkbox_only_flip = ttk.Checkbutton( + self.room_settings_container, + text="Only Flip", + var=self.var_only_flip, + onvalue=1, + offvalue=0, + command=self.on_flip_only_flip, + ) + self.checkbox_rare = ttk.Checkbutton( + self.room_settings_container, + text="Rare", + var=self.var_rare, + onvalue=1, + offvalue=0, + command=self.on_flip_rare, + ) + self.checkbox_hard = ttk.Checkbutton( + self.room_settings_container, + text="Hard", + var=self.var_hard, + onvalue=1, + offvalue=0, + command=self.on_flip_hard, + ) + self.checkbox_liquid = ttk.Checkbutton( + self.room_settings_container, + text="Optimize Liquids", + var=self.var_liquid, + onvalue=1, + offvalue=0, + command=self.on_flip_liquid, + ) + self.checkbox_purge = ttk.Checkbutton( + self.room_settings_container, + text="Purge", + var=self.var_purge, + onvalue=1, + offvalue=0, + command=self.on_flip_purge, + ) + self.checkbox_dual = ttk.Checkbutton( + self.room_settings_container, + text="Dual", + var=self.var_dual, + onvalue=1, + offvalue=0, + command=self.on_flip_dual, + ) + + wrap = 400 + label_dual = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Whether this room has a backlayer.") + label_ignore = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room will never appear in-game.") + label_purge = tk.Label (self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, other rooms of this same template which were already loaded (eg, loaded from another file or appear first in this file) will not appear in-game when this room's file is loaded.") + label_rare = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room has a 5% chance of being used.") + label_hard = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room only appears in X-3 and X-4.") + label_liquid = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Mark this room as containing liquid to optimize the liquid engine.") + label_flip = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Creates two rooms, one which is horizontally flipped from the original.") + label_only_flip = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Like flip, but the original room is ignored.") + + self.checkbox_dual.grid(row=0, column=0, sticky="w") + label_dual.grid(row=1, column=0, sticky="nws") + self.checkbox_ignore.grid(row=2, column=0, sticky="w") + label_ignore.grid(row=3, column=0, sticky="nws") + self.checkbox_purge.grid(row=4, column=0, sticky="w") + label_purge.grid(row=5, column=0, sticky="nws") + self.checkbox_rare.grid(row=6, column=0, sticky="w") + label_rare.grid(row=7, column=0, sticky="nws") + self.checkbox_hard.grid(row=8, column=0, sticky="w") + label_hard.grid(row=9, column=0, sticky="nws") + self.checkbox_liquid.grid(row=10, column=0, sticky="w") + label_liquid.grid(row=11, column=0, sticky="nws") + self.checkbox_flip.grid(row=12, column=0, sticky="w") + label_flip.grid(row=12, column=0, sticky="nws") + self.checkbox_only_flip.grid(row=14, column=0, sticky="w") + label_only_flip.grid(row=15, column=0, sticky="nws") + + self.columnconfigure(0, weight=1) + + def reset(self): self.current_template_row = None self.current_template_column = None @@ -106,6 +215,22 @@ def set_current_template(self, template, row, column): self.room_combobox.set(template.room_chunk.name or "room " + (template.room_index + 1)) self.room_combobox.current(template.room_index) self.template_container.grid() + + current_settings = template.room_chunk.settings + self.set_dual(TemplateSetting.DUAL in current_settings) + self.set_flip(TemplateSetting.FLIP in current_settings) + self.set_purge(TemplateSetting.PURGE in current_settings) + self.set_only_flip( + TemplateSetting.ONLYFLIP in current_settings + ) + self.set_ignore( + TemplateSetting.IGNORE in current_settings + ) + self.set_rare(TemplateSetting.RARE in current_settings) + self.set_hard(TemplateSetting.HARD in current_settings) + self.set_liquid( + TemplateSetting.LIQUID in current_settings + ) else: self.set_empty_cell(row, column) @@ -115,6 +240,80 @@ def set_empty_cell(self, row, column): self.template_combobox.set("None") self.template_container.grid_remove() + def flip_setting(self, setting, value): + self.on_flip_setting(setting, value, self.current_template_row, self.current_template_column) + + def on_flip_ignore(self): + self.flip_setting(TemplateSetting.IGNORE, self.ignore()) + + def on_flip_liquid(self): + self.flip_setting(TemplateSetting.LIQUID, self.liquid()) + + def on_flip_hard(self): + self.flip_setting(TemplateSetting.HARD, self.hard()) + + def on_flip_rare(self): + self.flip_setting(TemplateSetting.RARE, self.rare()) + + def on_flip_flip(self): + self.flip_setting(TemplateSetting.FLIP, self.flip()) + + def on_flip_only_flip(self): + self.flip_setting(TemplateSetting.ONLYFLIP, self.only_flip()) + + def on_flip_purge(self): + self.flip_setting(TemplateSetting.PURGE, self.purge()) + + def on_flip_dual(self): + self.flip_setting(TemplateSetting.DUAL, self.dual()) + + def ignore(self): + return int(self.var_ignore.get()) == 1 + + def liquid(self): + return int(self.var_liquid.get()) == 1 + + def hard(self): + return int(self.var_hard.get()) == 1 + + def rare(self): + return int(self.var_rare.get()) == 1 + + def flip(self): + return int(self.var_flip.get()) == 1 + + def only_flip(self): + return int(self.var_only_flip.get()) == 1 + + def purge(self): + return int(self.var_purge.get()) == 1 + + def dual(self): + return int(self.var_dual.get()) == 1 + + def set_ignore(self, ignore): + self.var_ignore.set(ignore and 1 or 0) + + def set_liquid(self, liquid): + self.var_liquid.set(liquid and 1 or 0) + + def set_hard(self, hard): + self.var_hard.set(hard and 1 or 0) + + def set_rare(self, rare): + self.var_rare.set(rare and 1 or 0) + + def set_flip(self, flip): + self.var_flip.set(flip and 1 or 0) + + def set_only_flip(self, only_flip): + self.var_only_flip.set(only_flip and 1 or 0) + + def set_purge(self, purge): + self.var_purge.set(purge and 1 or 0) + + def set_dual(self, dual): + self.var_dual.set(dual and 1 or 0) class OptionsPanel(ttk.Frame): def __init__( @@ -128,6 +327,7 @@ def __init__( on_change_template_at, on_clear_template, on_select_room, + on_flip_setting, *args, **kwargs, ): @@ -140,6 +340,7 @@ def __init__( self.on_change_template_at = on_change_template_at self.on_clear_template = on_clear_template self.on_select_room = on_select_room + self.on_flip_setting = on_flip_setting self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) @@ -244,7 +445,7 @@ def update_grid_size(_): settings_row += 1 self.room_options = RoomOptions( - self, self.update_room_map_template, self.clear_template, self.on_select_room + self, self.update_room_map_template, self.clear_template, self.on_select_room, self.on_flip_setting ) self.room_options.grid(row=settings_row, column=1, sticky="news") self.room_options.grid_remove() diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 9ae4e51b..cb0b594d 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -146,6 +146,7 @@ def tab_selected(event): if str(tab) == "Full Level View": self.load_full_preview() if str(tab) == "Full Level Editor": + self.multi_room_editor_tab.update_templates() self.multi_room_editor_tab.redraw() self.tab_control.bind("<>", tab_selected) From 64509b07e510438390204bd58900a865b22ce452 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 22:03:20 -0700 Subject: [PATCH 44/61] Add scrollable frame for options panel. --- .../multi_room/options_panel.py | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 1cd0c123..53ce2b68 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -3,7 +3,7 @@ from modlunky2.config import Config from modlunky2.levels.level_templates import TemplateSetting -from modlunky2.ui.widgets import PopupWindow +from modlunky2.ui.widgets import PopupWindow, ScrollableFrameLegacy class RoomOptions(ttk.Frame): @@ -135,7 +135,7 @@ def __init__( command=self.on_flip_dual, ) - wrap = 400 + wrap = 350 label_dual = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Whether this room has a backlayer.") label_ignore = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room will never appear in-game.") label_purge = tk.Label (self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, other rooms of this same template which were already loaded (eg, loaded from another file or appear first in this file) will not appear in-game when this room's file is loaded.") @@ -345,6 +345,7 @@ def __init__( self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) self.columnconfigure(2, minsize=10) + self.rowconfigure(0, weight=1) self.room_map = [] self.templates = [] @@ -352,6 +353,14 @@ def __init__( self.button_for_selected_room = None self.button_for_selected_empty_room = None + + + # The tile palettes are loaded into here as buttons with their image + # as a tile and text as their value to grab when needed. + self.scrollview = ScrollableFrameLegacy(self, text="", width=50) + self.scrollview.scrollable_frame["width"] = 50 + self.scrollview.grid(row=0, column=1, sticky="news") + settings_row = 0 # Checkbox to toggle the visibility of the grid lines. @@ -365,13 +374,13 @@ def toggle_hide_grid(): settings_row += 1 tk.Checkbutton( - self, + self.scrollview.scrollable_frame, text="Hide grid lines", variable=hide_grid_var, onvalue=True, offvalue=False, command=toggle_hide_grid, - ).grid(row=settings_row, column=1, sticky="nw", pady=5) + ).grid(row=settings_row, column=0, sticky="nw", pady=5) # Checkbox to toggle the visibility of the grid lines on room boundaries. hide_room_grid_var = tk.IntVar() @@ -383,17 +392,17 @@ def toggle_hide_room_grid(): settings_row += 1 tk.Checkbutton( - self, + self.scrollview.scrollable_frame, text="Hide room lines", variable=hide_room_grid_var, onvalue=True, offvalue=False, command=toggle_hide_room_grid, - ).grid(row=settings_row, column=1, sticky="nw", pady=5) + ).grid(row=settings_row, column=0, sticky="nw", pady=5) settings_row += 1 - grid_size_frame = tk.Frame(self) - grid_size_frame.grid(row=settings_row, column=1, sticky="nw", pady=5) + grid_size_frame = tk.Frame(self.scrollview.scrollable_frame) + grid_size_frame.grid(row=settings_row, column=0, sticky="nw", pady=5) grid_size_frame.columnconfigure(0, weight=1) grid_size_var = tk.StringVar() grid_size_var.set(str(zoom_level)) @@ -411,7 +420,7 @@ def toggle_hide_room_grid(): to=200, orient=tk.HORIZONTAL, variable=grid_size_var, - length=390, + length=370, showvalue=False, ) grid_size_scale.grid(row=1, column=0, sticky="nwe") @@ -424,9 +433,9 @@ def update_grid_size(_): settings_row += 1 - self.room_type_frame = tk.Frame(self) + self.room_type_frame = tk.Frame(self.scrollview.scrollable_frame) self.room_type_frame.grid( - row=settings_row, column=1, sticky="news", padx=10, pady=10 + row=settings_row, column=0, sticky="news", padx=10, pady=10 ) self.room_view_size = 30 @@ -445,9 +454,9 @@ def update_grid_size(_): settings_row += 1 self.room_options = RoomOptions( - self, self.update_room_map_template, self.clear_template, self.on_select_room, self.on_flip_setting + self.scrollview.scrollable_frame, self.update_room_map_template, self.clear_template, self.on_select_room, self.on_flip_setting ) - self.room_options.grid(row=settings_row, column=1, sticky="news") + self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() def update_room_map_template(self, template_index, row, column): From c007cbb88c2fe24c69f11a6036dd46470b545b51 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 22:28:05 -0700 Subject: [PATCH 45/61] Add creating rooms to map. --- .../multi_room/multi_room_editor_tab.py | 52 ++++++++++++++++++- .../multi_room/options_panel.py | 2 +- .../vanilla_levels/vanilla_level_editor.py | 5 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 19471d7c..fe82919e 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -39,6 +39,7 @@ def __init__( on_delete_tilecode, on_select_palette_tile, on_modify_room, + on_add_room, *args, **kwargs ): @@ -51,6 +52,7 @@ def __init__( self.on_delete_tilecode = on_delete_tilecode self.on_select_palette_tile = on_select_palette_tile self.on_modify_room = on_modify_room + self.on_add_room = on_add_room self.lvl = None self.lvl_biome = None @@ -244,7 +246,6 @@ def change_template_at(self, row, col, template, template_index): ) if template_draw_item: if template_draw_item.width_in_rooms + col > 10: - # TODO: add error dialog. win = PopupWindow("Cannot use this room template", self.modlunky_config) lbl = ttk.Label( win, @@ -414,6 +415,55 @@ def change_room_at(self, room_index, row, col): if template_item is None: return + if room_index >= len(template_item.template.rooms): + + win = PopupWindow("Add Room", self.modlunky_config) + + + lbl = ttk.Label( + win, + text="Create a new room in " + template_item.template.name + ".", + ) + lbl.grid(row=0, column=0) + + values_frame = tk.Frame(win) + values_frame.grid(row=1, column=0, sticky="nw") + + name_label = tk.Label(values_frame, text="Name: ") + name_label.grid(row=0, column=0, sticky="ne", pady=2) + + name_entry = tk.Entry(values_frame) + name_entry.grid(row=0, column=1, sticky="nwe", pady=2) + + separator = ttk.Separator(win) + separator.grid(row=2, column=0, columnspan=3, pady=5, sticky="news") + + buttons = ttk.Frame(win) + buttons.grid(row=3, column=0, columnspan=2, sticky="news") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + def insert_then_destroy(): + name = name_entry.get() + new_room = self.on_add_room(template_item.template_index, None if name == "" else name) + + template_item.room_index = room_index + template_item.room_chunk = new_room + + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() + win.destroy() + + ok_button = ttk.Button( + buttons, text="Create", command=insert_then_destroy + ) + ok_button.grid(row=0, column=0, pady=5, sticky="news") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="news") + + return + template_item.room_index = room_index template_item.room_chunk = template_item.template.rooms[room_index] diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 53ce2b68..7b661cf0 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -211,7 +211,7 @@ def set_current_template(self, template, row, column): self.template_combobox.set(template.template.name) self.room_combobox["values"] = [ room.name or "room " + (index + 1) for index, room in enumerate(template.template.rooms) - ] + ] + ["Create New"] self.room_combobox.set(template.room_chunk.name or "room " + (template.room_index + 1)) self.room_combobox.current(template.room_index) self.template_container.grid() diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index cb0b594d..44f5a72d 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -176,6 +176,7 @@ def multiroom_zoom_change(new_zoom): self.delete_tilecode, self.multiroom_editor_selected_tile, self.multiroom_editor_modified_room, + self.on_insert_room, ) self.variables_tab = VariablesTab( self.tab_control, @@ -1115,7 +1116,7 @@ def on_select_file(self, lvl): if self.last_selected_tab == "Full Level View": self.load_full_preview() - def on_insert_room(self, parent_index): + def on_insert_room(self, parent_index, name = None): room_template = self.template_list[parent_index] # Set default prompt based on parent name roomsize_key = "normal: 10x8" @@ -1132,7 +1133,7 @@ def on_insert_room(self, parent_index): back_layer = [ ["0" for _ in range(room_type.x_size)] for _ in range(room_type.y_size) ] - new_room = RoomInstance("new room", [], front_layer, back_layer) + new_room = RoomInstance(name or "new room", [], front_layer, back_layer) room_template.rooms.append(new_room) self.changes_made() return new_room From 213232bdd89d5da7f1931dfd657b899b5e9890f9 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 23:17:01 -0700 Subject: [PATCH 46/61] Added Rename/Delete/Duplicate buttons. --- .../multi_room/multi_room_editor_tab.py | 140 +++++++++++++++-- .../multi_room/options_panel.py | 141 ++++++++++++++---- .../vanilla_levels/vanilla_level_editor.py | 5 +- 3 files changed, 244 insertions(+), 42 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index fe82919e..5c011cf3 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -40,6 +40,9 @@ def __init__( on_select_palette_tile, on_modify_room, on_add_room, + on_duplicate_room, + on_rename_room, + on_delete_room, *args, **kwargs ): @@ -53,6 +56,9 @@ def __init__( self.on_select_palette_tile = on_select_palette_tile self.on_modify_room = on_modify_room self.on_add_room = on_add_room + self.on_duplicate_room = on_duplicate_room + self.on_rename_room = on_rename_room + self.on_delete_room = on_delete_room self.lvl = None self.lvl_biome = None @@ -135,6 +141,9 @@ def toggle_panel_hidden(): self.clear_template_at, self.change_room_at, self.room_setting_change_at, + self.duplicate_room, + self.rename_room, + self.delete_room, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -190,10 +199,10 @@ def __set_zoom(self, zoom): self.tile_image_map = {} self.redraw() - def __get_template_draw_item(self, template, template_index, row, column): + def __get_chunk_for_template_draw_item(self, template, template_index, row, column): chunk_index = None if len(template.rooms) == 0: - return None + return None, None valid_rooms = [ index for index, room in enumerate(template.rooms) @@ -226,9 +235,15 @@ def __get_template_draw_item(self, template, template_index, row, column): if len(valid_rooms) > 0: chunk_index = valid_rooms[0] else: - return None + return None, None chunk = template.rooms[chunk_index] + return chunk_index, chunk + + def __get_template_draw_item(self, template, template_index, row, column): + chunk_index, chunk = self.__get_chunk_for_template_draw_item( + template, template_index, row, column + ) if chunk is None or len(chunk.front) == 0: return None return TemplateDrawItem( @@ -416,10 +431,8 @@ def change_room_at(self, room_index, row, col): return if room_index >= len(template_item.template.rooms): - win = PopupWindow("Add Room", self.modlunky_config) - lbl = ttk.Label( win, text="Create a new room in " + template_item.template.name + ".", @@ -445,18 +458,20 @@ def change_room_at(self, room_index, row, col): def insert_then_destroy(): name = name_entry.get() - new_room = self.on_add_room(template_item.template_index, None if name == "" else name) + new_room = self.on_add_room( + template_item.template_index, None if name == "" else name + ) template_item.room_index = room_index template_item.room_chunk = new_room - self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.options_panel.set_templates( + self.template_draw_map, self.room_templates + ) self.redraw() win.destroy() - ok_button = ttk.Button( - buttons, text="Create", command=insert_then_destroy - ) + ok_button = ttk.Button(buttons, text="Create", command=insert_then_destroy) ok_button.grid(row=0, column=0, pady=5, sticky="news") cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) @@ -470,6 +485,96 @@ def insert_then_destroy(): self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() + def duplicate_room(self, row, col): + template_item = self.template_draw_map[row][col] + new_room = self.on_duplicate_room( + template_item.template_index, template_item.room_index + ) + + template_item.room_index = len(template_item.template.rooms) - 1 + template_item.room_chunk = new_room + + self.options_panel.set_templates(self.template_draw_map, self.room_templates) + self.redraw() + + def rename_room(self, row, col): + win = PopupWindow("Edit Name", self.modlunky_config) + + template_item = self.template_draw_map[row][col] + + item_name = "" + item_name = template_item.room_chunk.name or "" + + col1_lbl = ttk.Label(win, text="Name: ") + col1_ent = ttk.Entry(win) + col1_ent.insert(0, item_name) # Default to rooms current name + col1_lbl.grid(row=0, column=0, padx=2, pady=2, sticky="nse") + col1_ent.grid(row=0, column=1, padx=2, pady=2, sticky="news") + + def update_then_destroy(): + if col1_ent.get() != "": + self.on_rename_room( + template_item.template_index, + template_item.room_index, + col1_ent.get(), + ) + self.options_panel.set_templates( + self.template_draw_map, self.room_templates + ) + + win.destroy() + + separator = ttk.Separator(win) + separator.grid(row=1, column=0, columnspan=2, pady=5, sticky="news") + + buttons = ttk.Frame(win) + buttons.grid(row=2, column=0, columnspan=2, sticky="news") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + ok_button = ttk.Button(buttons, text="Rename", command=update_then_destroy) + ok_button.grid(row=0, column=0, pady=5, sticky="news") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="news") + + def delete_room(self, row, col): + template_item = self.template_draw_map[row][col] + + win = PopupWindow("Delete Room", self.modlunky_config) + + def delete_then_destroy(): + self.on_delete_room(template_item.template_index, template_item.room_index) + + # chunk_index, chunk = self.__get_chunk_for_template_draw_item(template_item.template, template_item.template_index, row, col) + + # if chunk_index is not None and chunk is not None: + # template_item.chunk_index = chunk_index + # template_item.chunk = chunk + + # self.options_panel.set_templates(self.template_draw_map, self.room_templates) + # self.redraw() + # else: + # self.clear_template_at(row, col) + win.destroy() + + lbl2 = ttk.Label(win, text="Are you sure you want to delete this room?") + lbl2.grid(row=0, column=0) + + separator = ttk.Separator(win) + separator.grid(row=1, column=0, columnspan=3, pady=5, sticky="news") + + buttons = ttk.Frame(win) + buttons.grid(row=2, column=0, columnspan=2, sticky="news") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + ok_button = ttk.Button(buttons, text="Delete", command=delete_then_destroy) + ok_button.grid(row=0, column=0, pady=5, sticky="news") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="news") + def room_setting_change_at(self, setting, value, row, col): template_item = self.template_draw_map[row][col] @@ -508,7 +613,7 @@ def delete_tilecode(self, tile_name, tile_code): def room_was_deleted(self, template_index, chunk_index): replaced = False - for _, template_row in enumerate(self.template_draw_map): + for row, template_row in enumerate(self.template_draw_map): for col, template in enumerate(template_row): if template is None: continue @@ -516,13 +621,20 @@ def room_was_deleted(self, template_index, chunk_index): template.template_index == template_index and template.room_index == chunk_index ): - new_draw_item = get_template_draw_item( - template.template, template_index + new_draw_item = self.__get_template_draw_item( + template.template, template_index, row, col ) template_row[col] = new_draw_item replaced = True + elif ( + template.template_index == template_index + and template.room_index > chunk_index + ): + template.room_index -= 1 if replaced: - self.options_panel.set_templates(self.template_draw_map) + self.options_panel.set_templates( + self.template_draw_map, self.room_templates + ) self.redraw() def canvas_click(self, canvas_index, row, column, is_primary): diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 7b661cf0..26bb06bd 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -14,6 +14,9 @@ def __init__( on_clear_template, on_select_room, on_flip_setting, + on_duplicate_room, + on_rename_room, + on_delete_room, *args, **kwargs, ): @@ -25,6 +28,9 @@ def __init__( self.on_clear_template = on_clear_template self.on_select_room = on_select_room self.on_flip_setting = on_flip_setting + self.on_duplicate_room = on_duplicate_room + self.on_rename_room = on_rename_room + self.on_delete_room = on_delete_room self.current_template_row = None self.current_template_column = None @@ -42,7 +48,9 @@ def __init__( self.template_combobox["values"] = ["None"] self.template_combobox.set("None") self.template_combobox["state"] = "readonly" - self.template_combobox.bind("<>", lambda _: self.select_template()) + self.template_combobox.bind( + "<>", lambda _: self.select_template() + ) setting_row += 1 @@ -59,8 +67,26 @@ def __init__( self.room_combobox["state"] = "readonly" self.room_combobox.bind("<>", lambda _: self.select_room()) + buttons_container = tk.Frame(self.template_container) + buttons_container.grid(row=2, column=0, sticky="news") + + duplicate_button = ttk.Button( + buttons_container, text="Duplicate", command=self.duplicate_room + ) + duplicate_button.grid(row=0, column=1, pady=5, sticky="news") + + rename_button = ttk.Button( + buttons_container, text="Rename", command=self.rename_room + ) + rename_button.grid(row=0, column=0, pady=5, sticky="news") + + delete_button = ttk.Button( + buttons_container, text="Delete", command=self.delete_room + ) + delete_button.grid(row=0, column=2, pady=5, sticky="news") + self.room_settings_container = tk.Frame(self.template_container) - self.room_settings_container.grid(row=2, column=0, sticky="news") + self.room_settings_container.grid(row=3, column=0, sticky="news") self.var_ignore = tk.IntVar() self.var_flip = tk.IntVar() @@ -136,14 +162,54 @@ def __init__( ) wrap = 350 - label_dual = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Whether this room has a backlayer.") - label_ignore = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room will never appear in-game.") - label_purge = tk.Label (self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, other rooms of this same template which were already loaded (eg, loaded from another file or appear first in this file) will not appear in-game when this room's file is loaded.") - label_rare = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room has a 5% chance of being used.") - label_hard = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="If checked, this room only appears in X-3 and X-4.") - label_liquid = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Mark this room as containing liquid to optimize the liquid engine.") - label_flip = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Creates two rooms, one which is horizontally flipped from the original.") - label_only_flip = tk.Label(self.room_settings_container, wraplength=wrap, justify=tk.LEFT, text="Like flip, but the original room is ignored.") + label_dual = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="Whether this room has a backlayer.", + ) + label_ignore = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="If checked, this room will never appear in-game.", + ) + label_purge = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="If checked, other rooms of this same template which were already loaded (eg, loaded from another file or appear first in this file) will not appear in-game when this room's file is loaded.", + ) + label_rare = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="If checked, this room has a 5% chance of being used.", + ) + label_hard = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="If checked, this room only appears in X-3 and X-4.", + ) + label_liquid = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="Mark this room as containing liquid to optimize the liquid engine.", + ) + label_flip = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="Creates two rooms, one which is horizontally flipped from the original.", + ) + label_only_flip = tk.Label( + self.room_settings_container, + wraplength=wrap, + justify=tk.LEFT, + text="Like flip, but the original room is ignored.", + ) self.checkbox_dual.grid(row=0, column=0, sticky="w") label_dual.grid(row=1, column=0, sticky="nws") @@ -164,7 +230,6 @@ def __init__( self.columnconfigure(0, weight=1) - def reset(self): self.current_template_row = None self.current_template_column = None @@ -189,7 +254,18 @@ def select_template(self): def select_room(self): room_index = self.room_combobox.current() - self.on_select_room(room_index, self.current_template_row, self.current_template_column) + self.on_select_room( + room_index, self.current_template_row, self.current_template_column + ) + + def duplicate_room(self): + self.on_duplicate_room(self.current_template_row, self.current_template_column) + + def rename_room(self): + self.on_rename_room(self.current_template_row, self.current_template_column) + + def delete_room(self): + self.on_delete_room(self.current_template_row, self.current_template_column) def clear_templates(self): self.template_combobox["values"] = ["None"] @@ -210,9 +286,12 @@ def set_current_template(self, template, row, column): if template: self.template_combobox.set(template.template.name) self.room_combobox["values"] = [ - room.name or "room " + (index + 1) for index, room in enumerate(template.template.rooms) + room.name or "room " + (index + 1) + for index, room in enumerate(template.template.rooms) ] + ["Create New"] - self.room_combobox.set(template.room_chunk.name or "room " + (template.room_index + 1)) + self.room_combobox.set( + template.room_chunk.name or "room " + (template.room_index + 1) + ) self.room_combobox.current(template.room_index) self.template_container.grid() @@ -220,17 +299,11 @@ def set_current_template(self, template, row, column): self.set_dual(TemplateSetting.DUAL in current_settings) self.set_flip(TemplateSetting.FLIP in current_settings) self.set_purge(TemplateSetting.PURGE in current_settings) - self.set_only_flip( - TemplateSetting.ONLYFLIP in current_settings - ) - self.set_ignore( - TemplateSetting.IGNORE in current_settings - ) + self.set_only_flip(TemplateSetting.ONLYFLIP in current_settings) + self.set_ignore(TemplateSetting.IGNORE in current_settings) self.set_rare(TemplateSetting.RARE in current_settings) self.set_hard(TemplateSetting.HARD in current_settings) - self.set_liquid( - TemplateSetting.LIQUID in current_settings - ) + self.set_liquid(TemplateSetting.LIQUID in current_settings) else: self.set_empty_cell(row, column) @@ -241,7 +314,9 @@ def set_empty_cell(self, row, column): self.template_container.grid_remove() def flip_setting(self, setting, value): - self.on_flip_setting(setting, value, self.current_template_row, self.current_template_column) + self.on_flip_setting( + setting, value, self.current_template_row, self.current_template_column + ) def on_flip_ignore(self): self.flip_setting(TemplateSetting.IGNORE, self.ignore()) @@ -315,6 +390,7 @@ def set_purge(self, purge): def set_dual(self, dual): self.var_dual.set(dual and 1 or 0) + class OptionsPanel(ttk.Frame): def __init__( self, @@ -328,6 +404,9 @@ def __init__( on_clear_template, on_select_room, on_flip_setting, + on_duplicate_room, + on_rename_room, + on_delete_room, *args, **kwargs, ): @@ -341,6 +420,9 @@ def __init__( self.on_clear_template = on_clear_template self.on_select_room = on_select_room self.on_flip_setting = on_flip_setting + self.on_duplicate_room = on_duplicate_room + self.on_rename_room = on_rename_room + self.on_delete_room = on_delete_room self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) @@ -353,8 +435,6 @@ def __init__( self.button_for_selected_room = None self.button_for_selected_empty_room = None - - # The tile palettes are loaded into here as buttons with their image # as a tile and text as their value to grab when needed. self.scrollview = ScrollableFrameLegacy(self, text="", width=50) @@ -454,7 +534,14 @@ def update_grid_size(_): settings_row += 1 self.room_options = RoomOptions( - self.scrollview.scrollable_frame, self.update_room_map_template, self.clear_template, self.on_select_room, self.on_flip_setting + self.scrollview.scrollable_frame, + self.update_room_map_template, + self.clear_template, + self.on_select_room, + self.on_flip_setting, + self.on_duplicate_room, + self.on_rename_room, + self.on_delete_room, ) self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 44f5a72d..ed41b0e7 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -177,6 +177,9 @@ def multiroom_zoom_change(new_zoom): self.multiroom_editor_selected_tile, self.multiroom_editor_modified_room, self.on_insert_room, + self.on_duplicate_room, + self.on_rename_room, + self.on_delete_room, ) self.variables_tab = VariablesTab( self.tab_control, @@ -1116,7 +1119,7 @@ def on_select_file(self, lvl): if self.last_selected_tab == "Full Level View": self.load_full_preview() - def on_insert_room(self, parent_index, name = None): + def on_insert_room(self, parent_index, name=None): room_template = self.template_list[parent_index] # Set default prompt based on parent name roomsize_key = "normal: 10x8" From f7a8422c7cae95499201dfa11dac6e32f3c4bbd0 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 23:19:51 -0700 Subject: [PATCH 47/61] Fix flip checkbox not showing. --- .../ui/levels/vanilla_levels/multi_room/options_panel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 26bb06bd..45edbda3 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -224,7 +224,7 @@ def __init__( self.checkbox_liquid.grid(row=10, column=0, sticky="w") label_liquid.grid(row=11, column=0, sticky="nws") self.checkbox_flip.grid(row=12, column=0, sticky="w") - label_flip.grid(row=12, column=0, sticky="nws") + label_flip.grid(row=13, column=0, sticky="nws") self.checkbox_only_flip.grid(row=14, column=0, sticky="w") label_only_flip.grid(row=15, column=0, sticky="nws") From e791caa4028d25825e121dcd32acb5d8bfd87793 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Fri, 15 Dec 2023 23:36:39 -0700 Subject: [PATCH 48/61] Refresh filetree when making changes that edit its contents. --- .../multi_room/multi_room_editor_tab.py | 16 +++++++--------- .../vanilla_levels/vanilla_level_editor.py | 6 ++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 5c011cf3..4e2f6e00 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -39,6 +39,7 @@ def __init__( on_delete_tilecode, on_select_palette_tile, on_modify_room, + on_change_filetree, on_add_room, on_duplicate_room, on_rename_room, @@ -55,6 +56,7 @@ def __init__( self.on_delete_tilecode = on_delete_tilecode self.on_select_palette_tile = on_select_palette_tile self.on_modify_room = on_modify_room + self.on_change_filetree = on_change_filetree self.on_add_room = on_add_room self.on_duplicate_room = on_duplicate_room self.on_rename_room = on_rename_room @@ -497,6 +499,8 @@ def duplicate_room(self, row, col): self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() + self.on_change_filetree() + def rename_room(self, row, col): win = PopupWindow("Edit Name", self.modlunky_config) @@ -522,6 +526,8 @@ def update_then_destroy(): self.template_draw_map, self.room_templates ) + self.on_change_filetree() + win.destroy() separator = ttk.Separator(win) @@ -546,16 +552,8 @@ def delete_room(self, row, col): def delete_then_destroy(): self.on_delete_room(template_item.template_index, template_item.room_index) - # chunk_index, chunk = self.__get_chunk_for_template_draw_item(template_item.template, template_item.template_index, row, col) - - # if chunk_index is not None and chunk is not None: - # template_item.chunk_index = chunk_index - # template_item.chunk = chunk + self.on_change_filetree() - # self.options_panel.set_templates(self.template_draw_map, self.room_templates) - # self.redraw() - # else: - # self.clear_template_at(row, col) win.destroy() lbl2 = ttk.Label(win, text="Are you sure you want to delete this room?") diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index ed41b0e7..fa5fe568 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -176,6 +176,7 @@ def multiroom_zoom_change(new_zoom): self.delete_tilecode, self.multiroom_editor_selected_tile, self.multiroom_editor_modified_room, + self.multiroom_editor_changed_filetree, self.on_insert_room, self.on_duplicate_room, self.on_rename_room, @@ -608,6 +609,11 @@ def multiroom_editor_modified_room(self, template_draw_item): self.room_select(None) self.changes_made() + def multiroom_editor_changed_filetree(self): + self.level_list_panel.reset() + self.level_list_panel.set_rooms(self.template_list) + self.room_select(None) + def save_requested(self): if self.save_needed: msg_box = tk.messagebox.askquestion( From 11fca4276cad6e386ebe45f5da24e70c8ec34c78 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 16 Dec 2023 00:44:51 -0700 Subject: [PATCH 49/61] Flip the layers of some rooms to match the rooms they connect to. --- .../multi_room/multi_room_editor_tab.py | 59 ++++++++++-- .../multi_room/options_panel.py | 90 +++++++++++++++++-- 2 files changed, 137 insertions(+), 12 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 4e2f6e00..682922f1 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -11,6 +11,7 @@ from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.multi_room.options_panel import OptionsPanel +from modlunky2.ui.levels.vanilla_levels.multi_room.reversed_rooms import REVERSED_ROOMS from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import ( find_roommap, get_template_draw_item, @@ -68,6 +69,7 @@ def __init__( self.tile_image_map = {} self.room_templates = [] self.template_draw_map = [] + self.reverse_layers = True self.zoom_level = zoom @@ -146,6 +148,7 @@ def toggle_panel_hidden(): self.duplicate_room, self.rename_room, self.delete_room, + self.toggle_reverse_layers, ) side_panel_tab_control.add(self.palette_panel, text="Tiles") side_panel_tab_control.add(self.options_panel, text="Settings") @@ -184,6 +187,10 @@ def redraw(self): self.show_intro() self.draw_canvas() + def toggle_reverse_layers(self, reverse): + self.reverse_layers = reverse + self.redraw() + def update_templates(self): self.options_panel.set_templates(self.template_draw_map, self.room_templates) @@ -647,14 +654,24 @@ def canvas_click(self, canvas_index, row, column, is_primary): chunk = template_draw_item.room_chunk - if canvas_index == 1 and TemplateSetting.DUAL not in chunk.settings: + backlayer_canvas = 1 + if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: + backlayer_canvas = 0 + + if ( + canvas_index == backlayer_canvas + and TemplateSetting.DUAL not in chunk.settings + ): # Do not draw on backlayer of non-dual room. return tile_name, tile_code = self.palette_panel.selected_tile(is_primary) x_offset, y_offset = self.offset_for_tile(tile_name, tile_code, self.zoom_level) - layer = [chunk.front, chunk.back][canvas_index] + layers = [chunk.front, chunk.back] + if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: + layers = [chunk.back, chunk.front] + layer = layers[canvas_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: @@ -693,11 +710,21 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): chunk = template_draw_item.room_chunk - if canvas_index == 1 and TemplateSetting.DUAL not in chunk.settings: + backlayer_canvas = 1 + if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: + backlayer_canvas = 0 + + if ( + canvas_index == backlayer_canvas + and TemplateSetting.DUAL not in chunk.settings + ): # Do not attempt to pull tile from backlayer of non-dual room. return - layer = [chunk.front, chunk.back][canvas_index] + layers = [chunk.front, chunk.back] + if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: + layers = [chunk.back, chunk.front] + layer = layers[canvas_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: @@ -796,17 +823,35 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): chunk = template_draw_item.room_chunk front = chunk.front back = chunk.back + frontlayer_canvas = 0 + backlayer_canvas = 1 + if ( + self.reverse_layers + and template_draw_item.template.name in REVERSED_ROOMS + ): + frontlayer_canvas = 1 + backlayer_canvas = 0 if TemplateSetting.ONLYFLIP in chunk.settings: front = list(map(lambda row: row[::-1], front)) back = list(map(lambda row: row[::-1], back)) - draw_chunk(0, room_column_index * 10, room_row_index * 8, front) + draw_chunk( + frontlayer_canvas, + room_column_index * 10, + room_row_index * 8, + front, + ) if TemplateSetting.DUAL in chunk.settings: - draw_chunk(1, room_column_index * 10, room_row_index * 8, back) + draw_chunk( + backlayer_canvas, + room_column_index * 10, + room_row_index * 8, + back, + ) else: for r in range(template_draw_item.height_in_rooms): for c in range(template_draw_item.width_in_rooms): self.canvas.draw_background_over_room( - 1, + backlayer_canvas, self.lvl_biome, room_row_index + r, room_column_index + c, diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 45edbda3..6309f4ee 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -3,6 +3,7 @@ from modlunky2.config import Config from modlunky2.levels.level_templates import TemplateSetting +from modlunky2.ui.levels.vanilla_levels.multi_room.reversed_rooms import REVERSED_ROOMS from modlunky2.ui.widgets import PopupWindow, ScrollableFrameLegacy @@ -17,6 +18,7 @@ def __init__( on_duplicate_room, on_rename_room, on_delete_room, + on_update_reverse_layers, *args, **kwargs, ): @@ -31,6 +33,7 @@ def __init__( self.on_duplicate_room = on_duplicate_room self.on_rename_room = on_rename_room self.on_delete_room = on_delete_room + self.on_update_reverse_layers = on_update_reverse_layers self.current_template_row = None self.current_template_column = None @@ -57,18 +60,64 @@ def __init__( self.template_container = tk.Frame(self) self.template_container.grid(row=setting_row, column=0, sticky="news") + template_setting_row = 0 + room_label = tk.Label(self.template_container, text="Room:") - room_label.grid(row=0, column=0, sticky="w") + room_label.grid(row=template_setting_row, column=0, sticky="w") + + template_setting_row += 1 self.room_combobox = ttk.Combobox(self.template_container, height=25) - self.room_combobox.grid(row=1, column=0, sticky="nsw") + self.room_combobox.grid(row=template_setting_row, column=0, sticky="nsw") self.room_combobox["values"] = [] self.room_combobox.set("") self.room_combobox["state"] = "readonly" self.room_combobox.bind("<>", lambda _: self.select_room()) + template_setting_row += 1 + + self.reverse_layers_container = tk.Frame(self.template_container) + self.reverse_layers_container.grid( + row=template_setting_row, column=0, sticky="news" + ) + + template_setting_row += 1 + + self.var_reverse_layers = tk.IntVar() + self.var_reverse_layers.set(True) + self.checkbox_reverse_layers = ttk.Checkbutton( + self.reverse_layers_container, + text="Reverse Layers", + var=self.var_reverse_layers, + onvalue=1, + offvalue=0, + command=self.on_flip_reverse_layers, + ) + + self.checkbox_reverse_layers.grid(row=0, column=0, sticky="news") + + wrap = 350 + self.reverse_layers_description_on = tk.Label( + self.reverse_layers_container, + wraplength=wrap, + justify=tk.LEFT, + text="The layers of this room are being reversed to match with the setrooms connected to it. Turn this off to disable this behavior.", + ) + self.reverse_layers_description_off = tk.Label( + self.reverse_layers_container, + wraplength=wrap, + justify=tk.LEFT, + text="The layers of this room can be reversed to match with the setrooms connected to it. Turn this on to enable this behavior.", + ) + self.reverse_layers_description_on.grid(row=1, column=0, sticky="nws") + self.reverse_layers_description_off.grid(row=2, column=0, sticky="nws") + buttons_container = tk.Frame(self.template_container) - buttons_container.grid(row=2, column=0, sticky="news") + buttons_container.grid(row=template_setting_row, column=0, sticky="news") + + self.configure_reverse_rooms_description() + + template_setting_row += 1 duplicate_button = ttk.Button( buttons_container, text="Duplicate", command=self.duplicate_room @@ -86,7 +135,11 @@ def __init__( delete_button.grid(row=0, column=2, pady=5, sticky="news") self.room_settings_container = tk.Frame(self.template_container) - self.room_settings_container.grid(row=3, column=0, sticky="news") + self.room_settings_container.grid( + row=template_setting_row, column=0, sticky="news" + ) + + template_setting_row += 1 self.var_ignore = tk.IntVar() self.var_flip = tk.IntVar() @@ -161,7 +214,6 @@ def __init__( command=self.on_flip_dual, ) - wrap = 350 label_dual = tk.Label( self.room_settings_container, wraplength=wrap, @@ -237,6 +289,26 @@ def reset(self): self.template_container.grid_remove() self.clear_templates() + def configure_reverse_rooms_container(self): + if self.current_template_item is None: + return + if self.current_template_item.template.name in REVERSED_ROOMS: + self.reverse_layers_container.grid() + else: + self.reverse_layers_container.grid_remove() + + def configure_reverse_rooms_description(self): + if self.reverse_layers(): + self.reverse_layers_description_on.grid() + self.reverse_layers_description_off.grid_remove() + else: + self.reverse_layers_description_on.grid_remove() + self.reverse_layers_description_off.grid() + + def on_flip_reverse_layers(self): + self.configure_reverse_rooms_description() + self.on_update_reverse_layers(self.reverse_layers()) + def select_template(self): template_index = self.template_combobox.current() @@ -278,12 +350,14 @@ def set_templates(self, templates): template.name for template in templates ] self.current_template_item = None + self.configure_reverse_rooms_container() def set_current_template(self, template, row, column): self.current_template_item = template self.current_template_row = row self.current_template_column = column if template: + self.configure_reverse_rooms_container() self.template_combobox.set(template.template.name) self.room_combobox["values"] = [ room.name or "room " + (index + 1) @@ -342,6 +416,9 @@ def on_flip_purge(self): def on_flip_dual(self): self.flip_setting(TemplateSetting.DUAL, self.dual()) + def reverse_layers(self): + return int(self.var_reverse_layers.get()) == 1 + def ignore(self): return int(self.var_ignore.get()) == 1 @@ -407,6 +484,7 @@ def __init__( on_duplicate_room, on_rename_room, on_delete_room, + on_update_reverse_layers, *args, **kwargs, ): @@ -423,6 +501,7 @@ def __init__( self.on_duplicate_room = on_duplicate_room self.on_rename_room = on_rename_room self.on_delete_room = on_delete_room + self.on_update_reverse_layers = on_update_reverse_layers self.columnconfigure(0, minsize=10) self.columnconfigure(1, weight=1) @@ -542,6 +621,7 @@ def update_grid_size(_): self.on_duplicate_room, self.on_rename_room, self.on_delete_room, + self.on_update_reverse_layers, ) self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() From ad25def97593d01e5bea4e45cbf870575c01e21a Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 16 Dec 2023 20:50:17 -0700 Subject: [PATCH 50/61] Prepare multi canvas container for both tabs and multi canvas per tab. --- .../custom_levels/custom_level_editor.py | 14 +- .../levels/shared/multi_canvas_container.py | 263 ++++++++++-------- .../multi_room/multi_room_editor_tab.py | 32 ++- .../multi_room/options_panel.py | 32 +-- .../vanilla_levels/vanilla_level_editor.py | 16 +- 5 files changed, 210 insertions(+), 147 deletions(-) diff --git a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py index 470d00d6..66163535 100644 --- a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py +++ b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py @@ -15,7 +15,10 @@ from modlunky2.ui.levels.custom_levels.tile_sets import suggested_tiles_for_theme from modlunky2.ui.levels.shared.biomes import BIOME from modlunky2.ui.levels.shared.files_tree import FilesTree, PACK_LIST_TYPE, LEVEL_TYPE -from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer +from modlunky2.ui.levels.shared.multi_canvas_container import ( + MultiCanvasContainer, + CanvasIndex, +) from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom from modlunky2.utils import tb_info @@ -120,6 +123,7 @@ def __init__( editor_view, textures_dir, ["Foreground", "Background"], + [], self.zoom_level, self.canvas_click, self.canvas_shiftclick, @@ -549,7 +553,7 @@ def draw_layer(canvas_index, tile_codes): ) for index, tileset in enumerate(self.tile_codes): - draw_layer(index, tileset) + draw_layer(CanvasIndex(index, 0), tileset) # Click event on a canvas for either left or right click to replace the tile at the cursor's position with # the selected tile. @@ -565,11 +569,11 @@ def canvas_click(self, canvas_index, row, column, is_primary): x_offset, y_offset, ) - self.tile_codes[canvas_index][row][column] = tile_code + self.tile_codes[canvas_index.tab_index][row][column] = tile_code self.changes_made() def canvas_shiftclick(self, index, row, column, is_primary): - tile_code = self.tile_codes[index][row][column] + tile_code = self.tile_codes[index.tab_index][row][column] tile = self.tile_palette_map[tile_code] self.palette_panel.select_tile(tile[0], tile[2], is_primary) @@ -674,7 +678,7 @@ def delete_tilecode(self, tile_name, tile_code): for column in range(len(tile_code_matrix[row])): if str(tile_code_matrix[row][column]) == str(tile_code): self.canvas.replace_tile_at( - matrix_index, row, column, new_tile[1] + CanvasIndex(matrix_index, 0), row, column, new_tile[1] ) tile_code_matrix[row][column] = "0" self.usable_codes.append(str(tile_code)) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index c74b225e..aeac54ee 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -1,21 +1,29 @@ +from dataclasses import dataclass import tkinter as tk from tkinter import ttk +from typing import List from modlunky2.ui.levels.shared.level_canvas import LevelCanvas, GridRoom from modlunky2.utils import is_windows +@dataclass +class CanvasIndex: + tab_index: int + canvas_index: int + + class MultiCanvasContainer(tk.Frame): def __init__( self, parent, textures_dir, + tab_titles, canvas_titles, zoom_level, on_click=None, on_shiftclick=None, intro_text=None, - side_by_side=False, *args, **kwargs ): @@ -23,11 +31,15 @@ def __init__( self.on_click = on_click self.on_shiftclick = on_shiftclick - self.side_by_side = side_by_side self.columnconfigure(1, weight=1) self.rowconfigure(1, weight=1) + if tab_titles is None or len(tab_titles) == 0: + tab_titles = [""] + if canvas_titles is None or len(canvas_titles) == 0: + canvas_titles = [""] + scrollable_canvas = tk.Canvas(self, bg="#292929") scrollable_canvas.grid(row=0, column=0, rowspan=2, columnspan=2, sticky="news") scrollable_canvas.columnconfigure(0, weight=1) @@ -48,7 +60,7 @@ def __init__( scrollable_frame.columnconfigure(0, minsize=int(int(width) / 2)) scrollable_frame.columnconfigure(1, weight=1) - canvas_gaps = side_by_side and len(canvas_titles) - 1 or 1 + canvas_gaps = len(canvas_titles) - 1 for column in range(canvas_gaps): scrollable_frame.columnconfigure((column + 1) * 2, minsize=50) scrollable_frame.columnconfigure( @@ -84,6 +96,7 @@ def __init__( ) scrollable_canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) + self.scrollable_canvas = scrollable_canvas switches_container = tk.Frame(self, bg="#343434") switches_container.grid(row=0, column=0, sticky="nw") @@ -92,6 +105,7 @@ def __init__( self.canvases = [] self.labels = [] self.radio_buttons = [] + self.hidden_tabs = [] self.hidden_canvases = [] # Buttons to switch the active layer. @@ -101,38 +115,42 @@ def __init__( def switch_layer(): nonlocal switch_variable layer = switch_variable.get() - for index, canvas in enumerate(self.canvases): - if index == int(layer): - canvas.grid() + for tab_index, tab_of_canvases in enumerate(self.canvases): + if tab_index == int(layer): + for canvas in tab_of_canvases: + canvas.grid() else: - canvas.grid_remove() - - for index, canvas_title in enumerate(canvas_titles): - new_canvas = LevelCanvas( - scrollable_frame, - textures_dir, - zoom_level, - on_click - and ( - lambda row, column, is_primary, i=index: self.on_click( - i, row, column, is_primary - ) - ), - on_shiftclick - and ( - lambda row, column, is_primary, i=index: self.on_shiftclick( - i, row, column, is_primary - ) - ), - bg="#343434", - ) - new_canvas.grid(row=1, column=(side_by_side and (index * 2) or 0) + 1) - if index != 0 and not side_by_side: - new_canvas.grid_remove() - self.canvases.append(new_canvas) - - if len(canvas_titles) > 1: - if side_by_side: + for canvas in tab_of_canvases: + canvas.grid_remove() + + for tab_index, tab_title in enumerate(tab_titles): + tab_canvases = [] + self.canvases.append(tab_canvases) + for index, canvas_title in enumerate(canvas_titles): + new_canvas = LevelCanvas( + scrollable_frame, + textures_dir, + zoom_level, + on_click + and ( + lambda row, column, is_primary, i=CanvasIndex( + tab_index, index + ): self.on_click(i, row, column, is_primary) + ), + on_shiftclick + and ( + lambda row, column, is_primary, i=CanvasIndex( + tab_index, index + ): self.on_shiftclick(i, row, column, is_primary) + ), + bg="#343434", + ) + new_canvas.grid(row=1, column=index * 2 + 1) + if tab_index != 0: + new_canvas.grid_remove() + tab_canvases.append(new_canvas) + + if len(canvas_titles) > 1: label = tk.Label( scrollable_frame, text=canvas_title, @@ -142,19 +160,20 @@ def switch_layer(): label.grid(row=2, column=index * 2 + 1, sticky="news") # label.grid_remove() self.labels.append(label) - else: - switch_button = tk.Radiobutton( - switches_container, - text=canvas_title, - variable=switch_variable, - indicatoron=False, - value=str(index), - width=max(len(canvas_title), 10), - command=switch_layer, - ) - self.radio_buttons.append(switch_button) - switch_button.grid(column=index, row=0, sticky="new") + if len(tab_titles) > 1: + switch_button = tk.Radiobutton( + switches_container, + text=tab_title, + variable=switch_variable, + indicatoron=False, + value=str(tab_index), + width=max(len(tab_title), 10), + command=switch_layer, + ) + self.radio_buttons.append(switch_button) + + switch_button.grid(column=tab_index, row=0, sticky="new") switch_variable.set("0") @@ -189,17 +208,9 @@ def _on_mousewheel(self, event, hbar, vbar, canvas): self._scroll_vertical(scroll_dir, vbar, canvas) def _scroll_vertical(self, scroll_dir, scrollbar, canvas): - # If the scrollbar is max size don't bother scrolling - if scrollbar.get() == (0.0, 1.0): - return - canvas.yview_scroll(scroll_dir, "units") def _scroll_horizontal(self, scroll_dir, scrollbar, canvas): - # If the scrollbar is max size don't bother scrolling - if scrollbar.get() == (0.0, 1.0): - return - canvas.xview_scroll(scroll_dir, "units") def _bind_to_mousewheel(self, _event, hbar, vbar, canvas): @@ -226,42 +237,64 @@ def _unbind_from_mousewheel(self, _event, canvas): canvas.unbind_all("") def replace_tile_at(self, index, row, column, image, offset_x=0, offset_y=0): - self.canvases[index].replace_tile_at(row, column, image, offset_x, offset_y) + self.canvases[index.tab_index][index.canvas_index].replace_tile_at( + row, column, image, offset_x, offset_y + ) - def configure_size(self, width, height): - for canvas in self.canvases: - canvas.configure_size(width, height) + def configure_size(self, width, height, index=None): + if index is None: + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.configure_size(width, height) + else: + self.canvases[index.tab_index][index.canvas_index].configure_size( + width, height + ) def set_zoom(self, zoom_level): - for canvas in self.canvases: - canvas.set_zoom(zoom_level) + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.set_zoom(zoom_level) def clear(self): - for canvas in self.canvases: - canvas.clear() + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.clear() def hide_grid_lines(self, hide_grid_lines): - for canvas in self.canvases: - canvas.hide_grid_lines(hide_grid_lines) + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.hide_grid_lines(hide_grid_lines) def hide_room_lines(self, hide_room_lines): - for canvas in self.canvases: - canvas.hide_room_lines(hide_room_lines) + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.hide_room_lines(hide_room_lines) def draw_background(self, theme): - for canvas in self.canvases: - canvas.draw_background(theme) + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.draw_background(theme) - def draw_background_over_room(self, canvas_index, theme, row, col): - self.canvases[canvas_index].draw_background_over_room(theme, row, col) + def draw_background_over_room(self, index, theme, row, col): + self.canvases[index.tab_index][index.canvas_index].draw_background_over_room( + theme, row, col + ) def draw_grid(self, width=None): - for canvas in self.canvases: - canvas.draw_grid(width) - - def draw_room_grid(self, width=1, special_room_sizes: GridRoom = None): - for canvas in self.canvases: - canvas.draw_room_grid(width, special_room_sizes) + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.draw_grid(width) + + def draw_room_grid(self, width=1, special_room_sizes: List[GridRoom] = None): + for tab_of_canvases in self.canvases: + for canvas_index, canvas in enumerate(tab_of_canvases): + canvas.draw_room_grid( + width, + None + if special_room_sizes is None + else special_room_sizes[canvas_index], + ) def show_intro(self): if self.intro: @@ -271,48 +304,60 @@ def hide_intro(self): if self.intro: self.intro.grid_remove() + def hide_tab(self, tab_index, hide): + if hide: + if tab_index in self.hidden_tabs: + return + self.hidden_tabs.append(tab_index) + selected_tab = int(self.switch_variable.get()) + + for canvas in self.canvases[tab_index]: + canvas.grid_remove() + + self.radio_buttons[tab_index].grid_remove() + if tab_index == selected_tab: + for ind, tab_of_canvases in enumerate(self.canvases): + if ind != tab_index and ind not in self.hidden_tabs: + for canvas in tab_of_canvases: + canvas.grid() + self.switch_variable.set(str(ind)) + break + if len(self.hidden_tabs) >= len(self.canvases) - 1: + self.switches_container.grid_remove() + else: + if tab_index not in self.hidden_tabs: + return + self.hidden_tabs.remove(tab_index) + if len(self.canvases) - len(self.hidden_tabs) == 1: + for canvas in self.canvases[tab_index]: + canvas.grid() + self.radio_buttons[tab_index].grid() + if len(self.hidden_tabs) < len(self.canvases) - 1: + self.switches_container.grid() + def hide_canvas(self, canvas_index, hide): if hide: if canvas_index in self.hidden_canvases: return self.hidden_canvases.append(canvas_index) - selected_canvas = int(self.switch_variable.get()) - - self.canvases[canvas_index].grid_remove() - if self.side_by_side: - self.labels[canvas_index].grid_remove() - - if len(self.hidden_canvases) >= len(self.canvases) - 1: - for label in self.labels: - label.grid_remove() - else: - self.radio_buttons[canvas_index].grid_remove() - if canvas_index == selected_canvas: - for ind, canv in enumerate(self.canvases): - if ind != canvas_index and not ind in self.hidden_canvases: - canv.grid() - self.switch_variable.set(str(ind)) - break - if len(self.hidden_canvases) >= len(self.canvases) - 1: - self.switches_container.grid_remove() - elif self.side_by_side: - if not canvas_index in self.hidden_canvases: + for canvases in self.canvases: + canvases[canvas_index].grid_remove() + + self.labels[canvas_index].grid_remove() + + if len(self.hidden_canvases) >= len(self.labels) - 1: + for label in self.labels: + label.grid_remove() + + else: + if canvas_index not in self.hidden_canvases: return self.hidden_canvases.remove(canvas_index) - self.canvases[canvas_index].grid() + for canvases in self.canvases: + canvases[canvas_index].grid() self.labels[canvas_index].grid() - if len(self.hidden_canvases) < len(self.canvases) - 1: + if len(self.hidden_canvases) < len(self.labels) - 1: for index, label in enumerate(self.labels): if not index in self.hidden_canvases: label.grid() - else: - if not canvas_index in self.hidden_canvases: - return - self.hidden_canvases.remove(canvas_index) - if len(self.canvases) - len(self.hidden_canvases) == 1: - self.canvaes[canvas_index].grid() - - self.radio_buttons[canvas_index].grid() - if len(self.hidden_canvases) < len(self.canvases) - 1: - self.switches_container.grid() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 682922f1..cdcc787e 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -7,7 +7,10 @@ from modlunky2.config import Config from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.levels.shared.level_canvas import GridRoom -from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer +from modlunky2.ui.levels.shared.multi_canvas_container import ( + MultiCanvasContainer, + CanvasIndex, +) from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.multi_room.options_panel import OptionsPanel @@ -90,6 +93,7 @@ def __init__( editor_view, textures_dir, ["Foreground", "Background"], + [], self.zoom_level, self.canvas_click, self.canvas_shiftclick, @@ -659,7 +663,7 @@ def canvas_click(self, canvas_index, row, column, is_primary): backlayer_canvas = 0 if ( - canvas_index == backlayer_canvas + canvas_index.tab_index == backlayer_canvas and TemplateSetting.DUAL not in chunk.settings ): # Do not draw on backlayer of non-dual room. @@ -671,7 +675,7 @@ def canvas_click(self, canvas_index, row, column, is_primary): layers = [chunk.front, chunk.back] if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: layers = [chunk.back, chunk.front] - layer = layers[canvas_index] + layer = layers[canvas_index.tab_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: @@ -715,7 +719,7 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): backlayer_canvas = 0 if ( - canvas_index == backlayer_canvas + canvas_index.tab_index == backlayer_canvas and TemplateSetting.DUAL not in chunk.settings ): # Do not attempt to pull tile from backlayer of non-dual room. @@ -724,7 +728,7 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): layers = [chunk.front, chunk.back] if self.reverse_layers and template_draw_item.template.name in REVERSED_ROOMS: layers = [chunk.back, chunk.front] - layer = layers[canvas_index] + layer = layers[canvas_index.tab_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: @@ -786,7 +790,7 @@ def draw_canvas(self): ) ) - self.canvas.draw_room_grid(2, grid_sizes) + self.canvas.draw_room_grid(2, [grid_sizes]) # Draws all of the images of a layer on its canvas, and stores the images in # the proper index of tile_images so they can be removed from the grid when @@ -835,14 +839,14 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): front = list(map(lambda row: row[::-1], front)) back = list(map(lambda row: row[::-1], back)) draw_chunk( - frontlayer_canvas, + CanvasIndex(frontlayer_canvas, 0), room_column_index * 10, room_row_index * 8, front, ) if TemplateSetting.DUAL in chunk.settings: draw_chunk( - backlayer_canvas, + CanvasIndex(backlayer_canvas, 0), room_column_index * 10, room_row_index * 8, back, @@ -851,7 +855,7 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): for r in range(template_draw_item.height_in_rooms): for c in range(template_draw_item.width_in_rooms): self.canvas.draw_background_over_room( - backlayer_canvas, + CanvasIndex(backlayer_canvas, 0), self.lvl_biome, room_row_index + r, room_column_index + c, @@ -862,10 +866,16 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): ) if template is None: self.canvas.draw_background_over_room( - 0, self.lvl_biome, room_row_index, room_column_index + CanvasIndex(0, 0), + self.lvl_biome, + room_row_index, + room_column_index, ) self.canvas.draw_background_over_room( - 1, self.lvl_biome, room_row_index, room_column_index + CanvasIndex(1, 0), + self.lvl_biome, + room_row_index, + room_column_index, ) def template_item_at(self, row, col): diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 6309f4ee..85d17205 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -62,27 +62,11 @@ def __init__( template_setting_row = 0 - room_label = tk.Label(self.template_container, text="Room:") - room_label.grid(row=template_setting_row, column=0, sticky="w") - - template_setting_row += 1 - - self.room_combobox = ttk.Combobox(self.template_container, height=25) - self.room_combobox.grid(row=template_setting_row, column=0, sticky="nsw") - self.room_combobox["values"] = [] - self.room_combobox.set("") - self.room_combobox["state"] = "readonly" - self.room_combobox.bind("<>", lambda _: self.select_room()) - - template_setting_row += 1 - self.reverse_layers_container = tk.Frame(self.template_container) self.reverse_layers_container.grid( row=template_setting_row, column=0, sticky="news" ) - template_setting_row += 1 - self.var_reverse_layers = tk.IntVar() self.var_reverse_layers.set(True) self.checkbox_reverse_layers = ttk.Checkbutton( @@ -112,6 +96,22 @@ def __init__( self.reverse_layers_description_on.grid(row=1, column=0, sticky="nws") self.reverse_layers_description_off.grid(row=2, column=0, sticky="nws") + template_setting_row += 1 + + room_label = tk.Label(self.template_container, text="Room:") + room_label.grid(row=template_setting_row, column=0, sticky="w") + + template_setting_row += 1 + + self.room_combobox = ttk.Combobox(self.template_container, height=25) + self.room_combobox.grid(row=template_setting_row, column=0, sticky="nsw") + self.room_combobox["values"] = [] + self.room_combobox.set("") + self.room_combobox["state"] = "readonly" + self.room_combobox.bind("<>", lambda _: self.select_room()) + + template_setting_row += 1 + buttons_container = tk.Frame(self.template_container) buttons_container.grid(row=template_setting_row, column=0, sticky="news") diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index fa5fe568..76421f48 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -23,7 +23,10 @@ from modlunky2.ui.levels.shared.biomes import Biomes from modlunky2.ui.levels.shared.files_tree import FilesTree, PACK_LIST_TYPE, LEVEL_TYPE from modlunky2.ui.levels.shared.make_backup import make_backup -from modlunky2.ui.levels.shared.multi_canvas_container import MultiCanvasContainer +from modlunky2.ui.levels.shared.multi_canvas_container import ( + MultiCanvasContainer, + CanvasIndex, +) from modlunky2.ui.levels.shared.palette_panel import PalettePanel from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom from modlunky2.ui.levels.vanilla_levels.dual_util import make_dual, remove_dual @@ -256,6 +259,7 @@ def toggle_hide_grid(): self.preview_tab, textures_dir, ["Foreground", "Background"], + [], self.mag_full, intro_text="Select a level file to begin viewing", ) @@ -302,12 +306,12 @@ def toggle_hide_grid(): self.canvas = MultiCanvasContainer( vanilla_editor_container, textures_dir, + [], ["Foreground Area", "Background Area"], self.mag, self.canvas_click, self.canvas_shiftclick, "Select a room to begin editing", - side_by_side=True, ) self.canvas.grid(row=0, column=0, rowspan=4, columnspan=8, sticky="news") @@ -579,7 +583,7 @@ def get_setrooms(): logger.debug("%s Not Found", tile) self.full_level_preview_canvas.replace_tile_at( - layer_index, + CanvasIndex(layer_index, 0), room_y * 8 + currow, room_x * 10 + curcol, tile_image_full, @@ -772,11 +776,11 @@ def canvas_click( y_offset, ) - self.tile_codes[canvas_index][row][column] = tile_code + self.tile_codes[canvas_index.canvas_index][row][column] = tile_code self.changes_made() def canvas_shiftclick(self, canvas_index, row, column, is_primary): - tile_code = self.tile_codes[canvas_index][row][column] + tile_code = self.tile_codes[canvas_index.canvas_index][row][column] tile = self.tile_palette_map[tile_code] self.palette_panel.select_tile(tile[0], tile[2], is_primary) @@ -985,7 +989,7 @@ def room_select(self, _event): # Loads room when click if not parent node. tile_name, ) self.canvas.replace_tile_at( - canvas_index, + CanvasIndex(0, canvas_index), row_index, column_index, tile_image, From 06f97bf6e9505866192770b4d33a1f6ca941dd1c Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 16 Dec 2023 21:04:28 -0700 Subject: [PATCH 51/61] Fix ONLYFLIP --- .../vanilla_levels/multi_room/multi_room_editor_tab.py | 7 ++++--- .../ui/levels/vanilla_levels/multi_room/reversed_rooms.py | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/modlunky2/ui/levels/vanilla_levels/multi_room/reversed_rooms.py diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index cdcc787e..c65e1430 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -678,9 +678,10 @@ def canvas_click(self, canvas_index, row, column, is_primary): layer = layers[canvas_index.tab_index] tile_row = row - room_row * 8 tile_col = column - room_col * 10 + data_tile_col = tile_col if TemplateSetting.ONLYFLIP in chunk.settings: - tile_col = 9 - tile_col - layer[tile_row][tile_col] = tile_code + data_tile_col = template_draw_item.width_in_rooms * 10 - 1 - tile_col + layer[tile_row][data_tile_col] = tile_code self.on_modify_room(template_draw_item) for r, room_rows in enumerate(self.template_draw_map): @@ -732,7 +733,7 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): tile_row = row - room_row * 8 tile_col = column - room_col * 10 if TemplateSetting.ONLYFLIP in chunk.settings: - tile_col = 9 - tile_col + tile_col = template_draw_item.width_in_rooms * 10 - 1 - tile_col tile_code = layer[tile_row][tile_col] tile = self.tile_palette_map[tile_code] diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/reversed_rooms.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/reversed_rooms.py new file mode 100644 index 00000000..5eca95ea --- /dev/null +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/reversed_rooms.py @@ -0,0 +1,7 @@ +REVERSED_ROOMS = [ + "palaceofpleasure_1-1", + "palaceofpleasure_3-2", + "udjatentrance", + "challenge_entrance", + "blackmarket_exit", +] From 209b26f2925538c19595abad1c0a2d6f38e541e2 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 16 Dec 2023 23:22:17 -0700 Subject: [PATCH 52/61] Split different parts of the room map into different canvases. --- .../levels/shared/multi_canvas_container.py | 26 +- src/modlunky2/ui/levels/shared/setrooms.py | 20 +- .../multi_room/multi_room_editor_tab.py | 430 ++++++++++-------- .../multi_room/options_panel.py | 264 ++++++----- .../vanilla_levels/multi_room/room_map.py | 120 +++-- 5 files changed, 480 insertions(+), 380 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index aeac54ee..1d6cdb8d 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -192,6 +192,7 @@ def switch_layer(): ) intro_label.place(relx=0.5, rely=0.5, anchor="center") + def _on_mousewheel(self, event, hbar, vbar, canvas): scroll_dir = None if event.num == 5 or event.delta == -120: @@ -271,20 +272,26 @@ def hide_room_lines(self, hide_room_lines): for canvas in tab_of_canvases: canvas.hide_room_lines(hide_room_lines) - def draw_background(self, theme): - for tab_of_canvases in self.canvases: - for canvas in tab_of_canvases: - canvas.draw_background(theme) + def draw_background(self, theme, index = None): + if index is None: + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.draw_background(theme) + else: + self.canvases[index.tab_index][index.canvas_index].draw_background(theme) def draw_background_over_room(self, index, theme, row, col): self.canvases[index.tab_index][index.canvas_index].draw_background_over_room( theme, row, col ) - def draw_grid(self, width=None): - for tab_of_canvases in self.canvases: - for canvas in tab_of_canvases: - canvas.draw_grid(width) + def draw_grid(self, width=None, index=None): + if index is None: + for tab_of_canvases in self.canvases: + for canvas in tab_of_canvases: + canvas.draw_grid(width) + else: + self.canvases[index.tab_index][index.canvas_index].draw_grid(width) def draw_room_grid(self, width=1, special_room_sizes: List[GridRoom] = None): for tab_of_canvases in self.canvases: @@ -295,6 +302,9 @@ def draw_room_grid(self, width=1, special_room_sizes: List[GridRoom] = None): if special_room_sizes is None else special_room_sizes[canvas_index], ) + def draw_canvas_room_grid(self, canvas_index, width=1, special_room_sizes: GridRoom = None): + canvas = self.canvases[canvas_index.tab_index][canvas_index.canvas_index] + canvas.draw_room_grid(width, special_room_sizes) def show_intro(self): if self.intro: diff --git a/src/modlunky2/ui/levels/shared/setrooms.py b/src/modlunky2/ui/levels/shared/setrooms.py index fea45dd9..7ca17253 100644 --- a/src/modlunky2/ui/levels/shared/setrooms.py +++ b/src/modlunky2/ui/levels/shared/setrooms.py @@ -1,10 +1,15 @@ +from dataclasses import dataclass from collections import namedtuple from enum import Enum import re RoomCoords = namedtuple("RoomCoords", ["x", "y"]) -MatchedSetroom = namedtuple("MatchedSetroom", ["name", "coords"]) +MatchedSetroom = namedtuple("MatchedSetroom", ["name", "template", "coords"]) +@dataclass +class BaseTemplateData: + name: str + template: str class VANILLA_SETROOM_TYPE(Enum): NONE = "none" @@ -14,9 +19,12 @@ class VANILLA_SETROOM_TYPE(Enum): class BaseTemplate: - setroom = "setroom{y}-{x}" - challenge = "challenge_{y}-{x}" - palace = "palaceofpleasure_{y}-{x}" + setroom = BaseTemplateData("setroom", "setroom{y}-{x}") + challenge = BaseTemplateData("challenge", "challenge_{y}-{x}") + palace = BaseTemplateData("palace of pleasure", "palaceofpleasure_{y}-{x}") + # setroom = {"name":"setroom", "template":"setroom{y}-{x}"} + # challenge = {"name":"challenge", "template":"challenge_{y}-{x}"} + # palace = {"name":"palace of pleasure", "template":"palaceofpleasure_{y}-{x}"} class Setroom: @@ -36,9 +44,9 @@ def match_setroom(template, room): @staticmethod def find_setroom_in_list(template_list, room): for setroom in template_list: - match = Setroom.match_setroom(setroom, room) + match = Setroom.match_setroom(setroom.template, room) if match: - return MatchedSetroom(setroom, match) + return MatchedSetroom(setroom.name, setroom.template, match) return None @staticmethod diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index c65e1430..fcca4605 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -54,6 +54,7 @@ def __init__( super().__init__(parent, *args, **kwargs) self.modlunky_config = modlunky_config self.texture_fetcher = texture_fetcher + self.textures_dir = textures_dir self.on_zoom_change = on_zoom_change self.on_add_tilecode = on_add_tilecode @@ -179,9 +180,25 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.tile_image_map = {} self.room_templates = room_templates + self.template_draw_map = find_roommap(room_templates) + self.canvas.grid_remove() + + + self.canvas = MultiCanvasContainer( + self.editor_container, + self.textures_dir, + ["Foreground", "Background"], + [room.name for room in self.template_draw_map], + self.zoom_level, + self.canvas_click, + self.canvas_shiftclick, + intro_text="Select a level file to begin viewing", + ) + self.canvas.grid(row=0, column=0, columnspan=3, rowspan=2, sticky="news") + self.canvas.show_intro() self.canvas.clear() self.show_intro() - self.template_draw_map = find_roommap(room_templates) + self.options_panel.reset() self.options_panel.set_templates(self.template_draw_map, room_templates) self.draw_canvas() @@ -212,7 +229,7 @@ def __set_zoom(self, zoom): self.tile_image_map = {} self.redraw() - def __get_chunk_for_template_draw_item(self, template, template_index, row, column): + def __get_chunk_for_template_draw_item(self, template, template_index, map_index, row, column): chunk_index = None if len(template.rooms) == 0: return None, None @@ -225,20 +242,21 @@ def __get_chunk_for_template_draw_item(self, template, template_index, row, colu if row is not None and column is not None: for i in valid_rooms: room_used = False - for r, room_row in enumerate(self.template_draw_map): - for c, room in enumerate(room_row): - if room is None: - continue - if r == row and c == column: - continue - if ( - room.template_index == template_index - and room.room_index == i - ): - room_used = True + for m, draw_map in enumerate(self.template_draw_map): + for r, room_row in enumerate(draw_map.rooms): + for c, room in enumerate(room_row): + if room is None: + continue + if r == row and c == column and m == map_index: + continue + if ( + room.template_index == template_index + and room.room_index == i + ): + room_used = True + break + if room_used: break - if room_used: - break if not room_used: chunk_index = i @@ -253,9 +271,9 @@ def __get_chunk_for_template_draw_item(self, template, template_index, row, colu chunk = template.rooms[chunk_index] return chunk_index, chunk - def __get_template_draw_item(self, template, template_index, row, column): + def __get_template_draw_item(self, template, template_index, map_index, row, column): chunk_index, chunk = self.__get_chunk_for_template_draw_item( - template, template_index, row, column + template, template_index, map_index, row, column ) if chunk is None or len(chunk.front) == 0: return None @@ -268,9 +286,9 @@ def __get_template_draw_item(self, template, template_index, row, column): int(math.ceil(len(chunk.front) / 8)), ) - def change_template_at(self, row, col, template, template_index): + def change_template_at(self, map_index, row, col, template, template_index): template_draw_item = self.__get_template_draw_item( - template, template_index, row, col + template, template_index, map_index, row, col ) if template_draw_item: if template_draw_item.width_in_rooms + col > 10: @@ -294,7 +312,7 @@ def change_template_at(self, row, col, template, template_index): template, overlapping_row, overlapping_column, - ) = self.template_item_at(row + row_offset, col + col_offset) + ) = self.template_item_at(map_index, row + row_offset, col + col_offset) if template is not None and ( overlapping_row != row or overlapping_column != col ): @@ -316,53 +334,53 @@ def expand_to_width_if_necessary(room_map, width): row.append(None) expand_to_height_if_necessary( - self.template_draw_map, row + template_draw_item.height_in_rooms + self.template_draw_map[map_index].rooms, row + template_draw_item.height_in_rooms ) expand_to_width_if_necessary( - self.template_draw_map, col + template_draw_item.width_in_rooms + self.template_draw_map[map_index].rooms, col + template_draw_item.width_in_rooms ) for row_offset in range(template_draw_item.height_in_rooms): for col_offset in range(template_draw_item.width_in_rooms): if row_offset == 0 and col_offset == 0: continue _, overlapping_row, overlapping_column = self.template_item_at( - row + row_offset, col + col_offset + map_index, row + row_offset, col + col_offset ) if overlapping_row is None or overlapping_column is None: continue - self.template_draw_map[overlapping_row][ + self.template_draw_map[map_index].rooms[overlapping_row][ overlapping_column ] = None - self.template_draw_map[row][col] = template_draw_item - while len(self.template_draw_map) > 0: + self.template_draw_map[map_index].rooms[row][col] = template_draw_item + while len(self.template_draw_map[map_index].rooms) > 0: has_room = False - r = len(self.template_draw_map) - 1 - for c in range(len(self.template_draw_map[r])): - t, _, _ = self.template_item_at(r, c) + r = len(self.template_draw_map[map_index].rooms) - 1 + for c in range(len(self.template_draw_map[map_index].rooms[r])): + t, _, _ = self.template_item_at(map_index, r, c) if t is not None: has_room = True break if has_room: break - self.template_draw_map.pop() + self.template_draw_map[map_index].rooms.pop() while ( - len(self.template_draw_map) > 0 - and len(self.template_draw_map[0]) > 0 + len(self.template_draw_map[map_index].rooms) > 0 + and len(self.template_draw_map[map_index].rooms[0]) > 0 ): has_room = False - for r in range(len(self.template_draw_map)): - c = len(self.template_draw_map[r]) - 1 - t, _, _ = self.template_item_at(r, c) + for r in range(len(self.template_draw_map[map_index].rooms)): + c = len(self.template_draw_map[map_index].rooms[r]) - 1 + t, _, _ = self.template_item_at(map_index, r, c) if t is not None: has_room = True break if has_room: break - for r in self.template_draw_map: + for r in self.template_draw_map[map_index].rooms: r.pop() self.options_panel.set_templates( @@ -404,41 +422,42 @@ def update_then_destroy(): else: update_template() - def clear_template_at(self, row, col): - self.template_draw_map[row][col] = None + def clear_template_at(self, map_index, row, col): + current_map = self.template_draw_map[map_index].rooms + current_map[row][col] = None - while len(self.template_draw_map) > 0: + while len(current_map) > 0: has_room = False - r = len(self.template_draw_map) - 1 - for c in range(len(self.template_draw_map[r])): - t, _, _ = self.template_item_at(r, c) + r = len(current_map) - 1 + for c in range(len(current_map[r])): + t, _, _ = self.template_item_at(map_index, r, c) if t is not None: has_room = True break if has_room: break - self.template_draw_map.pop() + current_map.pop() - while len(self.template_draw_map) > 0 and len(self.template_draw_map[0]) > 0: + while len(current_map) > 0 and len(current_map[0]) > 0: has_room = False - for r in range(len(self.template_draw_map)): - c = len(self.template_draw_map[r]) - 1 - t, _, _ = self.template_item_at(r, c) + for r in range(len(current_map)): + c = len(current_map[r]) - 1 + t, _, _ = self.template_item_at(map_index, r, c) if t is not None: has_room = True break if has_room: break - for r in self.template_draw_map: + for r in current_map: r.pop() self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() - def change_room_at(self, room_index, row, col): - template_item = self.template_draw_map[row][col] + def change_room_at(self, room_index, map_index, row, col): + template_item = self.template_draw_map[map_index].rooms[row][col] if template_item is None: return @@ -498,8 +517,8 @@ def insert_then_destroy(): self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.redraw() - def duplicate_room(self, row, col): - template_item = self.template_draw_map[row][col] + def duplicate_room(self, map_index, row, col): + template_item = self.template_draw_map[map_index].rooms[row][col] new_room = self.on_duplicate_room( template_item.template_index, template_item.room_index ) @@ -512,10 +531,10 @@ def duplicate_room(self, row, col): self.on_change_filetree() - def rename_room(self, row, col): + def rename_room(self, map_index, row, col): win = PopupWindow("Edit Name", self.modlunky_config) - template_item = self.template_draw_map[row][col] + template_item = self.template_draw_map[map_index].rooms[row][col] item_name = "" item_name = template_item.room_chunk.name or "" @@ -555,8 +574,8 @@ def update_then_destroy(): cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) cancel_button.grid(row=0, column=1, pady=5, sticky="news") - def delete_room(self, row, col): - template_item = self.template_draw_map[row][col] + def delete_room(self, map_index, row, col): + template_item = self.template_draw_map[map_index].rooms[row][col] win = PopupWindow("Delete Room", self.modlunky_config) @@ -584,8 +603,8 @@ def delete_then_destroy(): cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) cancel_button.grid(row=0, column=1, pady=5, sticky="news") - def room_setting_change_at(self, setting, value, row, col): - template_item = self.template_draw_map[row][col] + def room_setting_change_at(self, setting, value, map_index, row, col): + template_item = self.template_draw_map[map_index].rooms[row][col] if template_item is None: return @@ -622,24 +641,25 @@ def delete_tilecode(self, tile_name, tile_code): def room_was_deleted(self, template_index, chunk_index): replaced = False - for row, template_row in enumerate(self.template_draw_map): - for col, template in enumerate(template_row): - if template is None: - continue - if ( - template.template_index == template_index - and template.room_index == chunk_index - ): - new_draw_item = self.__get_template_draw_item( - template.template, template_index, row, col - ) - template_row[col] = new_draw_item - replaced = True - elif ( - template.template_index == template_index - and template.room_index > chunk_index - ): - template.room_index -= 1 + for map_index, template_map in enumerate(self.template_draw_map): + for row, template_row in enumerate(template_map.rooms): + for col, template in enumerate(template_row): + if template is None: + continue + if ( + template.template_index == template_index + and template.room_index == chunk_index + ): + new_draw_item = self.__get_template_draw_item( + template.template, template_index, map_index, row, col + ) + template_row[col] = new_draw_item + replaced = True + elif ( + template.template_index == template_index + and template.room_index > chunk_index + ): + template.room_index -= 1 if replaced: self.options_panel.set_templates( self.template_draw_map, self.room_templates @@ -649,7 +669,7 @@ def room_was_deleted(self, template_index, chunk_index): def canvas_click(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 template_draw_item, room_row, room_col = self.template_item_at( - room_row, room_col + canvas_index.canvas_index, room_row, room_col ) if template_draw_item is None: @@ -684,29 +704,30 @@ def canvas_click(self, canvas_index, row, column, is_primary): layer[tile_row][data_tile_col] = tile_code self.on_modify_room(template_draw_item) - for r, room_rows in enumerate(self.template_draw_map): - for c, other_template_draw_item in enumerate(room_rows): - if other_template_draw_item is None: - continue - if ( - template_draw_item.template_index - == other_template_draw_item.template_index - and template_draw_item.room_index - == other_template_draw_item.room_index - ): - self.canvas.replace_tile_at( - canvas_index, - tile_row + r * 8, - tile_col + c * 10, - self.image_for_tile_code(tile_code), - x_offset, - y_offset, - ) + for map_index, template_map in enumerate(self.template_draw_map): + for r, room_rows in enumerate(template_map.rooms): + for c, other_template_draw_item in enumerate(room_rows): + if other_template_draw_item is None: + continue + if ( + template_draw_item.template_index + == other_template_draw_item.template_index + and template_draw_item.room_index + == other_template_draw_item.room_index + ): + self.canvas.replace_tile_at( + CanvasIndex(canvas_index.tab_index, map_index), + tile_row + r * 8, + tile_col + c * 10, + self.image_for_tile_code(tile_code), + x_offset, + y_offset, + ) def canvas_shiftclick(self, canvas_index, row, column, is_primary): room_row, room_col = row // 8, column // 10 template_draw_item, room_row, room_col = self.template_item_at( - room_row, room_col + canvas_index.canvas_index, room_row, room_col ) if template_draw_item is None: @@ -743,10 +764,7 @@ def canvas_shiftclick(self, canvas_index, row, column, is_primary): # Looks up the expected offset type and tile image size and computes the offset of the tile's anchor in the grid. def offset_for_tile(self, tile_name, tile_code, tile_size): - # tile_ref = self.tile_palette_map[tile_code] img = self.image_for_tile_code(tile_code) - # if tile_ref: - # img = tile_ref[1] if img: return self.texture_fetcher.adjust_texture_xy( img.width(), img.height(), tile_name, tile_size @@ -765,122 +783,132 @@ def hide_intro(self): def draw_canvas(self): if len(self.template_draw_map) == 0: return - if len(self.template_draw_map[0]) == 0: - return - height = len(self.template_draw_map) - width = len(self.template_draw_map[0]) self.canvas.clear() self.hide_intro() - self.canvas.configure_size(width * 10, height * 8) - - self.canvas.draw_background(self.lvl_biome) - self.canvas.draw_grid() - - grid_sizes = [] - for room_row_index, room_row in enumerate(self.template_draw_map): - for room_column_index, template_draw_item in enumerate(room_row): - if template_draw_item is None: - continue - grid_sizes.append( - GridRoom( - room_row_index, - room_column_index, - template_draw_item.width_in_rooms, - template_draw_item.height_in_rooms, + for map_index, draw_map in enumerate(self.template_draw_map): + draw_rooms = draw_map.rooms + if len(draw_rooms) == 0: + continue + if len(draw_rooms[0]) == 0: + continue + height = len(draw_rooms) + width = len(draw_rooms[0]) + + self.canvas.configure_size(width * 10, height * 8, CanvasIndex(0, map_index)) + self.canvas.configure_size(width * 10, height * 8, CanvasIndex(1, map_index)) + + self.canvas.draw_background(self.lvl_biome, CanvasIndex(0, map_index)) + self.canvas.draw_background(self.lvl_biome, CanvasIndex(1, map_index)) + self.canvas.draw_grid(index=CanvasIndex(0, map_index)) + self.canvas.draw_grid(index=CanvasIndex(1, map_index)) + + grid_sizes = [] + for room_row_index, room_row in enumerate(draw_rooms): + for room_column_index, template_draw_item in enumerate(room_row): + if template_draw_item is None: + continue + grid_sizes.append( + GridRoom( + room_row_index, + room_column_index, + template_draw_item.width_in_rooms, + template_draw_item.height_in_rooms, + ) ) - ) - self.canvas.draw_room_grid(2, [grid_sizes]) + # self.canvas.draw_room_grid(2, [grid_sizes]) + self.canvas.draw_canvas_room_grid(CanvasIndex(0, map_index), 2, grid_sizes) + self.canvas.draw_canvas_room_grid(CanvasIndex(1, map_index), 2, grid_sizes) - # Draws all of the images of a layer on its canvas, and stores the images in - # the proper index of tile_images so they can be removed from the grid when - # replaced with another tile. - def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): - for row_index, room_row in enumerate(tile_codes): - if row_index + chunk_start_y >= height * 8: - continue - for tile_index, tile in enumerate(room_row): - if tile_index + chunk_start_x >= width * 10: + # Draws all of the images of a layer on its canvas, and stores the images in + # the proper index of tile_images so they can be removed from the grid when + # replaced with another tile. + def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): + for row_index, room_row in enumerate(tile_codes): + if row_index + chunk_start_y >= height * 8: continue - tilecode = self.tile_palette_map[tile] - tile_name = tilecode[0].split(" ", 1)[0] - # tile_image = tilecode[1] - tile_image = self.image_for_tile_code(tile) - x_offset, y_offset = self.texture_fetcher.adjust_texture_xy( - tile_image.width(), - tile_image.height(), - tile_name, - self.zoom_level, - ) - self.canvas.replace_tile_at( - canvas_index, - row_index + chunk_start_y, - tile_index + chunk_start_x, - tile_image, - x_offset, - y_offset, - ) + for tile_index, tile in enumerate(room_row): + if tile_index + chunk_start_x >= width * 10: + continue + tilecode = self.tile_palette_map[tile] + tile_name = tilecode[0].split(" ", 1)[0] + # tile_image = tilecode[1] + tile_image = self.image_for_tile_code(tile) + x_offset, y_offset = self.texture_fetcher.adjust_texture_xy( + tile_image.width(), + tile_image.height(), + tile_name, + self.zoom_level, + ) + self.canvas.replace_tile_at( + canvas_index, + row_index + chunk_start_y, + tile_index + chunk_start_x, + tile_image, + x_offset, + y_offset, + ) - for room_row_index, room_row in enumerate(self.template_draw_map): - for room_column_index, template_draw_item in enumerate(room_row): - if template_draw_item: - chunk = template_draw_item.room_chunk - front = chunk.front - back = chunk.back - frontlayer_canvas = 0 - backlayer_canvas = 1 - if ( - self.reverse_layers - and template_draw_item.template.name in REVERSED_ROOMS - ): - frontlayer_canvas = 1 - backlayer_canvas = 0 - if TemplateSetting.ONLYFLIP in chunk.settings: - front = list(map(lambda row: row[::-1], front)) - back = list(map(lambda row: row[::-1], back)) - draw_chunk( - CanvasIndex(frontlayer_canvas, 0), - room_column_index * 10, - room_row_index * 8, - front, - ) - if TemplateSetting.DUAL in chunk.settings: + for room_row_index, room_row in enumerate(draw_rooms): + for room_column_index, template_draw_item in enumerate(room_row): + if template_draw_item: + chunk = template_draw_item.room_chunk + front = chunk.front + back = chunk.back + frontlayer_canvas = 0 + backlayer_canvas = 1 + if ( + self.reverse_layers + and template_draw_item.template.name in REVERSED_ROOMS + ): + frontlayer_canvas = 1 + backlayer_canvas = 0 + if TemplateSetting.ONLYFLIP in chunk.settings: + front = list(map(lambda row: row[::-1], front)) + back = list(map(lambda row: row[::-1], back)) draw_chunk( - CanvasIndex(backlayer_canvas, 0), + CanvasIndex(frontlayer_canvas, map_index), room_column_index * 10, room_row_index * 8, - back, + front, ) + if TemplateSetting.DUAL in chunk.settings: + draw_chunk( + CanvasIndex(backlayer_canvas, map_index), + room_column_index * 10, + room_row_index * 8, + back, + ) + else: + for r in range(template_draw_item.height_in_rooms): + for c in range(template_draw_item.width_in_rooms): + self.canvas.draw_background_over_room( + CanvasIndex(backlayer_canvas, map_index), + self.lvl_biome, + room_row_index + r, + room_column_index + c, + ) else: - for r in range(template_draw_item.height_in_rooms): - for c in range(template_draw_item.width_in_rooms): - self.canvas.draw_background_over_room( - CanvasIndex(backlayer_canvas, 0), - self.lvl_biome, - room_row_index + r, - room_column_index + c, - ) - else: - template, _, _ = self.template_item_at( - room_row_index, room_column_index - ) - if template is None: - self.canvas.draw_background_over_room( - CanvasIndex(0, 0), - self.lvl_biome, - room_row_index, - room_column_index, + template, _, _ = self.template_item_at( + map_index, room_row_index, room_column_index ) - self.canvas.draw_background_over_room( - CanvasIndex(1, 0), - self.lvl_biome, - room_row_index, - room_column_index, - ) - - def template_item_at(self, row, col): - for room_row_index, room_row in enumerate(self.template_draw_map): + if template is None: + self.canvas.draw_background_over_room( + CanvasIndex(0, map_index), + self.lvl_biome, + room_row_index, + room_column_index, + ) + self.canvas.draw_background_over_room( + CanvasIndex(1, map_index), + self.lvl_biome, + room_row_index, + room_column_index, + ) + + def template_item_at(self, map_index, row, col): + for room_row_index, room_row in enumerate(self.template_draw_map[map_index].rooms): if room_row_index > row: return None, None, None for room_column_index, template_draw_item in enumerate(room_row): diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 85d17205..39d23386 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -35,6 +35,7 @@ def __init__( self.on_delete_room = on_delete_room self.on_update_reverse_layers = on_update_reverse_layers + self.current_template_map_index = None self.current_template_row = None self.current_template_column = None self.current_template_item = None @@ -283,6 +284,7 @@ def __init__( self.columnconfigure(0, weight=1) def reset(self): + self.current_template_map_index = None self.current_template_row = None self.current_template_column = None self.current_template_item = None @@ -315,11 +317,12 @@ def select_template(self): if template_index == 0: self.clear_templates() self.on_clear_template( - self.current_template_row, self.current_template_column + self.current_template_map_index, self.current_template_row, self.current_template_column ) else: self.on_select_template( template_index - 1, + self.current_template_map_index, self.current_template_row, self.current_template_column, ) @@ -327,17 +330,17 @@ def select_template(self): def select_room(self): room_index = self.room_combobox.current() self.on_select_room( - room_index, self.current_template_row, self.current_template_column + room_index, self.current_template_map_index, self.current_template_row, self.current_template_column ) def duplicate_room(self): - self.on_duplicate_room(self.current_template_row, self.current_template_column) + self.on_duplicate_room(self.current_template_map_index, self.current_template_row, self.current_template_column) def rename_room(self): - self.on_rename_room(self.current_template_row, self.current_template_column) + self.on_rename_room(self.current_template_map_index, self.current_template_row, self.current_template_column) def delete_room(self): - self.on_delete_room(self.current_template_row, self.current_template_column) + self.on_delete_room(self.current_template_map_index, self.current_template_row, self.current_template_column) def clear_templates(self): self.template_combobox["values"] = ["None"] @@ -352,7 +355,8 @@ def set_templates(self, templates): self.current_template_item = None self.configure_reverse_rooms_container() - def set_current_template(self, template, row, column): + def set_current_template(self, template, map_index, row, column): + self.current_template_map_index = map_index self.current_template_item = template self.current_template_row = row self.current_template_column = column @@ -379,9 +383,10 @@ def set_current_template(self, template, row, column): self.set_hard(TemplateSetting.HARD in current_settings) self.set_liquid(TemplateSetting.LIQUID in current_settings) else: - self.set_empty_cell(row, column) + self.set_empty_cell(map_index, row, column) - def set_empty_cell(self, row, column): + def set_empty_cell(self, map_index, row, column): + self.current_template_map_index = map_index self.current_template_row = row self.current_template_column = column self.template_combobox.set("None") @@ -389,7 +394,7 @@ def set_empty_cell(self, row, column): def flip_setting(self, setting, value): self.on_flip_setting( - setting, value, self.current_template_row, self.current_template_column + setting, value, self.current_template_map_index, self.current_template_row, self.current_template_column ) def on_flip_ignore(self): @@ -626,12 +631,12 @@ def update_grid_size(_): self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() - def update_room_map_template(self, template_index, row, column): + def update_room_map_template(self, template_index, map_index, row, column): template = self.templates[template_index] - self.on_change_template_at(row, column, template, template_index) + self.on_change_template_at(map_index, row, column, template, template_index) - def clear_template(self, row, column): - self.on_clear_template(row, column) + def clear_template(self, map_index, row, column): + self.on_clear_template(map_index, row, column) def reset(self): self.button_for_selected_room = None @@ -644,26 +649,37 @@ def set_templates(self, room_map, templates): self.button_for_selected_empty_room = None self.room_options.grid_remove() # self.room_options.grid_remove() + room_row_start = 0 if self.room_map is not None: - for row_index in range(len(self.room_map) + 1): - self.room_type_frame.rowconfigure(row_index * 2, minsize=0) - if row_index != 0: - self.room_type_frame.rowconfigure(row_index * 2 - 1, minsize=0) + for template_map in self.room_map: + + for row_index in range(len(template_map.rooms) + 1): + self.room_type_frame.rowconfigure(room_row_start + row_index * 2, minsize=0) + if row_index + room_row_start != 0: + self.room_type_frame.rowconfigure(room_row_start + row_index * 2 - 1, minsize=0) + + room_row_start += (len(template_map.rooms) + 1) * 2 + self.room_map = room_map self.templates = templates self.room_options.set_templates(templates) + room_row_start = 0 if room_map is not None: - for row_index in range(len(room_map) + 1): - self.room_type_frame.rowconfigure( - row_index * 2, minsize=self.room_view_size - ) - if row_index != 0: + for template_map in room_map: + for row_index in range(len(template_map.rooms) + 1): self.room_type_frame.rowconfigure( - row_index * 2 - 1, minsize=self.room_view_padding + room_row_start + row_index * 2, minsize=self.room_view_size ) + if row_index != 0: + self.room_type_frame.rowconfigure( + room_row_start + row_index * 2 - 1, minsize=self.room_view_padding + ) + elif room_row_start != 0: + self.room_type_frame.rowconfigure(room_row_start + row_index * 2 - 1, minsize=self.room_view_size) + room_row_start += (len(template_map.rooms) + 1) * 2 for button in self.room_buttons: button.grid_remove() @@ -674,117 +690,123 @@ def set_templates(self, room_map, templates): self.room_buttons = [] self.edge_frames = [] - for row_index, template_row in enumerate(room_map): - for col_index, template in enumerate(template_row): - new_button = None - if template is None: - overlapping_template, _, _ = self.template_item_at( - room_map, row_index, col_index - ) - if overlapping_template is None: + room_row_start = 0 + for map_index, template_map in enumerate(room_map): + for row_index, template_row in enumerate(template_map.rooms): + for col_index, template in enumerate(template_row): + new_button = None + if template is None: + overlapping_template, _, _ = self.template_item_at( + template_map.rooms, row_index, col_index + ) + if overlapping_template is None: + new_button = tk.Button( + self.room_type_frame, + bg="#5A605A", + activebackground="#5A605A", + relief=tk.GROOVE, + ) + new_button.configure( + command=lambda nb=new_button, m=map_index, r=row_index, c=col_index: self.select_empty_cell( + nb, m, r, c + ) + ) + new_button.grid( + row=room_row_start + row_index * 2, column=col_index * 2, sticky="news" + ) + if ( + map_index == self.room_options.current_template_map_index and + row_index == self.room_options.current_template_row + and col_index == self.room_options.current_template_column + ): + self.button_for_selected_empty_room = new_button + self.room_options.set_empty_cell(map_index, row_index, col_index) + else: new_button = tk.Button( self.room_type_frame, - bg="#5A605A", - activebackground="#5A605A", + bg="#30F030", + activebackground="#30F030", relief=tk.GROOVE, ) new_button.configure( - command=lambda nb=new_button, r=row_index, c=col_index: self.select_empty_cell( - nb, r, c + command=lambda t=template, nb=new_button, m=map_index, r=row_index, c=col_index: self.select_template_item( + t, nb, m, r, c ) ) new_button.grid( - row=row_index * 2, column=col_index * 2, sticky="news" + row=room_row_start + row_index * 2, + column=col_index * 2, + rowspan=template.height_in_rooms * 2 - 1, + columnspan=template.width_in_rooms * 2 - 1, + sticky="news", ) if ( + map_index == self.room_options.current_template_map_index and row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column ): - self.button_for_selected_empty_room = new_button - self.room_options.set_empty_cell(row_index, col_index) - else: - new_button = tk.Button( - self.room_type_frame, - bg="#30F030", - activebackground="#30F030", + self.button_for_selected_room = new_button + self.room_options.set_current_template( + template, map_index, row_index, col_index + ) + if new_button is not None: + self.room_buttons.append(new_button) + + if len(template_row) < 10: + edge_frame = tk.Frame(self.room_type_frame) + edge_frame.grid( + row=room_row_start + row_index * 2, column=len(template_row) * 2, sticky="news" + ) + edge_frame.columnconfigure(0, weight=1) + edge_frame.rowconfigure(0, weight=1) + + edge_button = tk.Button( + edge_frame, + text="+", + bg="#A0C0A6", + activebackground="#A0C0A6", relief=tk.GROOVE, ) - new_button.configure( - command=lambda t=template, nb=new_button, r=row_index, c=col_index: self.select_template_item( - t, nb, r, c - ) + edge_button.grid(row=0, column=0, sticky="news") + edge_button.grid_remove() + edge_button.configure( + command=lambda m=map_index, r=row_index, c=len( + template_row + ): self.show_create_new_dialog(m, r, c) ) - new_button.grid( - row=row_index * 2, - column=col_index * 2, - rowspan=template.height_in_rooms * 2 - 1, - columnspan=template.width_in_rooms * 2 - 1, - sticky="news", + + edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) + edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + self.edge_frames.append(edge_frame) + + rooms = template_map.rooms + if len(rooms) > 0: + row = room_row_start + len(rooms) * 2 + for col in range(len(rooms[0])): + edge_frame = tk.Frame(self.room_type_frame) + edge_frame.grid(row=row, column=col * 2, sticky="news") + edge_frame.columnconfigure(0, weight=1) + edge_frame.rowconfigure(0, weight=1) + + edge_button = tk.Button( + edge_frame, + text="+", + bg="#A0C0A6", + activebackground="#A0C0A6", + relief=tk.GROOVE, ) - if ( - row_index == self.room_options.current_template_row - and col_index == self.room_options.current_template_column - ): - self.button_for_selected_room = new_button - self.room_options.set_current_template( - template, row_index, col_index + edge_button.grid(row=0, column=0, sticky="news") + edge_button.grid_remove() + edge_button.configure( + command=lambda r=len(rooms), c=col, m=map_index: self.show_create_new_dialog( + m, r, c ) - if new_button is not None: - self.room_buttons.append(new_button) - - if len(template_row) < 10: - edge_frame = tk.Frame(self.room_type_frame) - edge_frame.grid( - row=row_index * 2, column=len(template_row) * 2, sticky="news" - ) - edge_frame.columnconfigure(0, weight=1) - edge_frame.rowconfigure(0, weight=1) - - edge_button = tk.Button( - edge_frame, - text="+", - bg="#A0C0A6", - activebackground="#A0C0A6", - relief=tk.GROOVE, - ) - edge_button.grid(row=0, column=0, sticky="news") - edge_button.grid_remove() - edge_button.configure( - command=lambda r=row_index, c=len( - template_row - ): self.show_create_new_dialog(r, c) - ) - - edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) - self.edge_frames.append(edge_frame) - - if len(room_map) > 0: - row = len(room_map) * 2 - for col in range(len(room_map[0])): - edge_frame = tk.Frame(self.room_type_frame) - edge_frame.grid(row=row, column=col * 2, sticky="news") - edge_frame.columnconfigure(0, weight=1) - edge_frame.rowconfigure(0, weight=1) - - edge_button = tk.Button( - edge_frame, - text="+", - bg="#A0C0A6", - activebackground="#A0C0A6", - relief=tk.GROOVE, - ) - edge_button.grid(row=0, column=0, sticky="news") - edge_button.grid_remove() - edge_button.configure( - command=lambda r=len(room_map), c=col: self.show_create_new_dialog( - r, c ) - ) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) - self.edge_frames.append(edge_frame) + edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) + edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + self.edge_frames.append(edge_frame) + room_row_start += (len(template_map.rooms) + 1) * 2 self.highlight_selected_button() def reset_selected_button(self): @@ -811,21 +833,21 @@ def highlight_selected_button(self): ) self.room_options.grid() - def select_template_item(self, template_item, button, row, column): + def select_template_item(self, template_item, button, map_index, row, column): self.reset_selected_button() self.button_for_selected_room = button self.highlight_selected_button() - self.room_options.set_current_template(template_item, row, column) + self.room_options.set_current_template(template_item, map_index, row, column) self.room_options.grid() - def select_empty_cell(self, button, row, column): + def select_empty_cell(self, button, map_index, row, column): self.reset_selected_button() self.button_for_selected_empty_room = button self.highlight_selected_button() - self.room_options.set_empty_cell(row, column) + self.room_options.set_empty_cell(map_index, row, column) self.room_options.grid() - def show_create_new_dialog(self, row, column): + def show_create_new_dialog(self, map_index, row, column): win = PopupWindow("Add room", self.modlunky_config) lbl = ttk.Label(win, text="Select a template to add.") @@ -857,8 +879,8 @@ def add_then_destroy(): warning_label.grid() return - self.room_options.set_empty_cell(row, column) - self.update_room_map_template(template_index, row, column) + self.room_options.set_empty_cell(map_index, row, column) + self.update_room_map_template(template_index, map_index, row, column) win.destroy() ok_button = ttk.Button(buttons, text="Add", command=add_then_destroy) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index 836e6cfe..c201ec87 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -1,4 +1,6 @@ +from dataclasses import dataclass import math +from typing import List from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.levels.shared.setrooms import Setroom, MatchedSetroom @@ -11,6 +13,11 @@ TemplateDrawItem, ) +@dataclass +class RoomMap: + name: str + rooms: List[List[TemplateDrawItem]] + def get_template_draw_item(room_template, index): chunk_index = None @@ -68,9 +75,16 @@ def set_room(room_map, x, y, room): room_map[y][x] = room room_map = [] + setroom_start = 0 - for _, setroomtype in setrooms.items(): + challenge_map = None + + for name, setroomtype in setrooms.items(): + setroom_map = [] + room_map.append(RoomMap(name, setroom_map)) + if challenge_map is None or name == "challenge": + challenge_map = setroom_map for matchedtemplate in setroomtype: match = matchedtemplate.setroom x, y = match.coords.x, match.coords.y @@ -79,9 +93,9 @@ def set_room(room_map, x, y, room): matchedtemplate.template, templates.index(matchedtemplate.template) ) if template_item: - set_room(room_map, x, setroom_start + y, template_item) + set_room(setroom_map, x, setroom_start + y, template_item) - setroom_start = len(room_map) + # setroom_start = len(setroom_map) template_map = {} for index, room_template in enumerate(templates): @@ -89,7 +103,7 @@ def set_room(room_map, x, y, room): if template_item: template_map[room_template.name] = template_item - path_start = setroom_start + path_start = 0 entrance = template_map.get("entrance") entrance_drop = template_map.get("entrance_drop") path = template_map.get("path_normal") @@ -102,125 +116,140 @@ def set_room(room_map, x, y, room): path_tall = template_map.get("machine_tallroom_path") path_big = template_map.get("machine_bigroom_path") - more_rooms_start = path_start + more_rooms_start = 0 + + path_map = [] if entrance: - set_room(room_map, 0, path_start, entrance) + set_room(path_map, 0, path_start, entrance) more_rooms_start = path_start + 1 if path is None: if entrance_drop: - set_room(room_map, 1, path_start, entrance_drop) + set_room(path_map, 1, path_start, entrance_drop) more_rooms_start = path_start + 1 if path_exit: - set_room(room_map, 2, path_start, path_exit) + set_room(path_map, 2, path_start, path_exit) more_rooms_start = path_start + 1 if path_exit_notop: - set_room(room_map, 3, path_start, path_exit_notop) + set_room(path_map, 3, path_start, path_exit_notop) more_rooms_start = path_start + 1 else: cw = 1 - set_room(room_map, 1, path_start, path) + set_room(path_map, 1, path_start, path) if path_drop: cw = 2 - set_room(room_map, 2, path_start, path_drop) + set_room(path_map, 2, path_start, path_drop) if entrance_drop: - set_room(room_map, cw + 1, path_start, entrance_drop) + set_room(path_map, cw + 1, path_start, entrance_drop) big_top = 1 if path_wide: big_top = 2 - set_room(room_map, 0, path_start + 1, path_wide) + set_room(path_map, 0, path_start + 1, path_wide) has_big = False if path_big: has_big = True - set_room(room_map, 0, path_start + big_top, path_big) + set_room(path_map, 0, path_start + big_top, path_big) if path_drop_notop: - set_room(room_map, 2, path_start + 1, path_drop_notop) + set_room(path_map, 2, path_start + 1, path_drop_notop) if path_notop: - set_room(room_map, 2, path_start + 2, path_notop) + set_room(path_map, 2, path_start + 2, path_notop) if path_tall: - set_room(room_map, 3, path_start + 1, path_tall) + set_room(path_map, 3, path_start + 1, path_tall) er, ec = 3, 2 if not has_big: er, ec = 2, 0 if path_exit: - set_room(room_map, ec, path_start + er, path_exit) + set_room(path_map, ec, path_start + er, path_exit) ec += 1 if path_exit_notop: - set_room(room_map, ec, path_start + er, path_exit_notop) + set_room(path_map, ec, path_start + er, path_exit_notop) more_rooms_start = path_start + er + 1 olmecship_room = template_map.get("olmecship_room") if olmecship_room: for i, room in enumerate(room_map[more_rooms_start - 1]): if room is None: - set_room(room_map, i, more_rooms_start - 1, olmecship_room) + set_room(path_map, i, more_rooms_start - 1, olmecship_room) break + challenge_entrance = template_map.get("challenge_entrance") challenge_special = template_map.get("challenge_special") challenge_bottom = template_map.get("challenge_bottom") entrancer, entrancec = None, None + + if challenge_map is None: + challenge_map = path_map + more_rooms_start = len(challenge_map) if challenge_entrance: - for i, room in enumerate(room_map[more_rooms_start - 1]): + for i, room in enumerate(challenge_map[more_rooms_start - 1]): if room is None: entrancer, entrancec = more_rooms_start - 1, i - set_room(room_map, i, more_rooms_start - 1, challenge_entrance) + set_room(challenge_map, i, more_rooms_start - 1, challenge_entrance) break if entrancer is None: entrancer, entrancec = more_rooms_start, 0 - set_room(room_map, 0, more_rooms_start, challenge_entrance) + set_room(challenge_map, 0, more_rooms_start, challenge_entrance) more_rooms_start += 1 bottomr, bottomc = None, None if challenge_bottom: if entrancer is not None and entrancec is not None: - set_room(room_map, entrancec, entrancer + 1, challenge_bottom) + set_room(challenge_map, entrancec, entrancer + 1, challenge_bottom) bottomr, bottomc = entrancer + 1, entrancec more_rooms_start += 1 else: - set_room(room_map, 0, more_rooms_start, challenge_bottom) + set_room(challenge_map, 0, more_rooms_start, challenge_bottom) bottomr, bottomc = more_rooms_start, 0 more_rooms_start += 1 if challenge_special: if bottomc is not None and bottomr is not None: set_room( - room_map, - bottomc < len(room_map[0]) and bottomc + 1 or bottomc - 1, + challenge_map, + bottomc < len(challenge_map[0]) and bottomc + 1 or bottomc - 1, bottomr, challenge_special, ) elif entrancer is not None and entrancec is not None: cr, cc = entrancer + 1, entrancec if ( - entrancec < len(room_map[entrancer]) - and room_map[entrancer][entrancec + 1] is None + entrancec < len(challenge_map[entrancer]) + and challenge_map[entrancer][entrancec + 1] is None ): cr, cc = entrancer, entrancec + 1 - elif entrancec > 0 and room_map[entrancer][entrancec - 1] is None: + elif entrancec > 0 and challenge_map[entrancer][entrancec - 1] is None: cr, cc = entrancer, entrancec - 1 - set_room(room_map, cc, cr, challenge_special) + set_room(challenge_map, cc, cr, challenge_special) more_rooms_start = cr + 1 else: - set_room(room_map, 0, more_rooms_start, challenge_special) + set_room(challenge_map, 0, more_rooms_start, challenge_special) more_rooms_start += 1 + if len(path_map) > 0: + room_map.append(RoomMap("path", path_map)) + + + other_rooms_map = [] + bigroom_side = template_map.get("machine_bigroom_side") wideroom_side = template_map.get("machine_wideroom_side") tallroom_side = template_map.get("machine_tallroom_side") side = template_map.get("side") + more_rooms_start = 0 + sideroomsc, sideroomsr = 0, 0 sider, sidec = 0, 0 highest_room = 0 if bigroom_side: - set_room(room_map, 0, more_rooms_start, bigroom_side) + set_room(other_rooms_map, 0, more_rooms_start, bigroom_side) sideroomsc = 2 sideroomsr = 2 sider, sidec = 0, 2 highest_room = 2 if tallroom_side: - set_room(room_map, sideroomsc, more_rooms_start, tallroom_side) + set_room(other_rooms_map, sideroomsc, more_rooms_start, tallroom_side) sideroomsr = 2 sideroomsc += 1 sider, sidec = 0, sideroomsc @@ -233,9 +262,9 @@ def set_room(room_map, x, y, room): sider, sidec = wider + 1, widec if wider + 1 > highest_room: highest_room = wider + 1 - set_room(room_map, widec, more_rooms_start + wider, wideroom_side) + set_room(other_rooms_map, widec, more_rooms_start + wider, wideroom_side) if side: - set_room(room_map, sidec, more_rooms_start + sider, side) + set_room(other_rooms_map, sidec, more_rooms_start + sider, side) if sider + 1 > highest_room: highest_room = sider + 1 @@ -257,7 +286,7 @@ def set_room(room_map, x, y, room): top_room = template_map.get(room_pair[0]) r = 0 if top_room: - set_room(room_map, vertical_room_column, more_rooms_start, top_room) + set_room(other_rooms_map, vertical_room_column, more_rooms_start, top_room) r = 1 if vertical_max_height == 0: vertical_max_height = 1 @@ -265,7 +294,7 @@ def set_room(room_map, x, y, room): if bottom_room: if vertical_max_height < r + 1: vertical_max_height = r + 1 - set_room(room_map, vertical_room_column, more_rooms_start + r, bottom_room) + set_room(other_rooms_map, vertical_room_column, more_rooms_start + r, bottom_room) if top_room is not None or bottom_room is not None: vertical_room_column += 1 @@ -324,20 +353,23 @@ def set_room(room_map, x, y, room): for row in range(more_rooms_start, more_rooms_bottom + 1): if added_room: break - if len(room_map) <= row: + if len(other_rooms_map) <= row: break - for col, template_item in enumerate(room_map[row]): + for col, template_item in enumerate(other_rooms_map[row]): if template_item is None: - set_room(room_map, col, row, room) + set_room(other_rooms_map, col, row, room) added_room = True break if not added_room: - if len(room_map) > 0 and len(room_map[0]) < 3: - set_room(room_map, len(room_map[0]), more_rooms_start, room) + if len(other_rooms_map) > 0 and len(other_rooms_map[0]) < 3: + set_room(other_rooms_map, len(other_rooms_map[0]), more_rooms_start, room) else: more_rooms_start = more_rooms_bottom + 1 more_rooms_bottom = more_rooms_start - set_room(room_map, 0, more_rooms_start, room) + set_room(other_rooms_map, 0, more_rooms_start, room) + + if len(other_rooms_map) > 0: + room_map.append(RoomMap("other", other_rooms_map)) return room_map From f4348668018367dca35eed3bf03a896fe303b224 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sat, 16 Dec 2023 23:48:44 -0700 Subject: [PATCH 53/61] Verticalize it. --- .../levels/shared/multi_canvas_container.py | 25 ++++++++++++++----- .../multi_room/multi_room_editor_tab.py | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 1d6cdb8d..7b95807c 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -24,6 +24,7 @@ def __init__( on_click=None, on_shiftclick=None, intro_text=None, + vertical = False, *args, **kwargs ): @@ -62,14 +63,20 @@ def __init__( scrollable_frame.columnconfigure(1, weight=1) canvas_gaps = len(canvas_titles) - 1 for column in range(canvas_gaps): - scrollable_frame.columnconfigure((column + 1) * 2, minsize=50) + if vertical: + scrollable_frame.rowconfigure((column + 1) * 2, minsize=50) + else: + scrollable_frame.columnconfigure((column + 1) * 2, minsize=50) scrollable_frame.columnconfigure( - (canvas_gaps + 1) * 2, minsize=int(int(width) / 2) + (canvas_gaps + 1) * 2 if not vertical else 4, minsize=int(int(width) / 2) ) scrollable_frame.rowconfigure(0, minsize=int(int(height) / 2)) scrollable_frame.rowconfigure(1, weight=1) - scrollable_frame.rowconfigure(2, minsize=100) - scrollable_frame.rowconfigure(4, minsize=int(int(height) / 2)) + if not vertical: + scrollable_frame.rowconfigure(2, minsize=100) + if vertical: + scrollable_frame.rowconfigure((canvas_gaps + 1) * 2, minsize=50) + scrollable_frame.rowconfigure((canvas_gaps + 1) * 2 + 1 if vertical else 4, minsize=int(int(height) / 2)) # Scroll bars for scrolling the canvases. hbar = ttk.Scrollbar(self, orient="horizontal", command=scrollable_canvas.xview) @@ -145,7 +152,10 @@ def switch_layer(): ), bg="#343434", ) - new_canvas.grid(row=1, column=index * 2 + 1) + if vertical: + new_canvas.grid(row=index * 2 + 1, column=1, sticky="sw") + else: + new_canvas.grid(row=1, column=index * 2 + 1, sticky="sw") if tab_index != 0: new_canvas.grid_remove() tab_canvases.append(new_canvas) @@ -157,7 +167,10 @@ def switch_layer(): fg="white", bg="#343434", ) - label.grid(row=2, column=index * 2 + 1, sticky="news") + if vertical: + label.grid(row=(index + 1) * 2, column=1, sticky="nw") + else: + label.grid(row=2, column=index * 2 + 1, sticky="news") # label.grid_remove() self.labels.append(label) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index fcca4605..4b02381c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -193,6 +193,7 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.canvas_click, self.canvas_shiftclick, intro_text="Select a level file to begin viewing", + vertical = True, ) self.canvas.grid(row=0, column=0, columnspan=3, rowspan=2, sticky="news") self.canvas.show_intro() From 4f2352f80e9eb3013738064cd8816ea27d7958a1 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 00:00:57 -0700 Subject: [PATCH 54/61] Fix tiamat and CO. --- .../levels/shared/multi_canvas_container.py | 14 +-- src/modlunky2/ui/levels/shared/setrooms.py | 2 + .../multi_room/multi_room_editor_tab.py | 33 ++++--- .../multi_room/options_panel.py | 89 +++++++++++++------ .../vanilla_levels/multi_room/room_map.py | 17 ++-- 5 files changed, 109 insertions(+), 46 deletions(-) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 7b95807c..f87e12bb 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -24,7 +24,7 @@ def __init__( on_click=None, on_shiftclick=None, intro_text=None, - vertical = False, + vertical=False, *args, **kwargs ): @@ -76,7 +76,9 @@ def __init__( scrollable_frame.rowconfigure(2, minsize=100) if vertical: scrollable_frame.rowconfigure((canvas_gaps + 1) * 2, minsize=50) - scrollable_frame.rowconfigure((canvas_gaps + 1) * 2 + 1 if vertical else 4, minsize=int(int(height) / 2)) + scrollable_frame.rowconfigure( + (canvas_gaps + 1) * 2 + 1 if vertical else 4, minsize=int(int(height) / 2) + ) # Scroll bars for scrolling the canvases. hbar = ttk.Scrollbar(self, orient="horizontal", command=scrollable_canvas.xview) @@ -205,7 +207,6 @@ def switch_layer(): ) intro_label.place(relx=0.5, rely=0.5, anchor="center") - def _on_mousewheel(self, event, hbar, vbar, canvas): scroll_dir = None if event.num == 5 or event.delta == -120: @@ -285,7 +286,7 @@ def hide_room_lines(self, hide_room_lines): for canvas in tab_of_canvases: canvas.hide_room_lines(hide_room_lines) - def draw_background(self, theme, index = None): + def draw_background(self, theme, index=None): if index is None: for tab_of_canvases in self.canvases: for canvas in tab_of_canvases: @@ -315,7 +316,10 @@ def draw_room_grid(self, width=1, special_room_sizes: List[GridRoom] = None): if special_room_sizes is None else special_room_sizes[canvas_index], ) - def draw_canvas_room_grid(self, canvas_index, width=1, special_room_sizes: GridRoom = None): + + def draw_canvas_room_grid( + self, canvas_index, width=1, special_room_sizes: GridRoom = None + ): canvas = self.canvases[canvas_index.tab_index][canvas_index.canvas_index] canvas.draw_room_grid(width, special_room_sizes) diff --git a/src/modlunky2/ui/levels/shared/setrooms.py b/src/modlunky2/ui/levels/shared/setrooms.py index 7ca17253..fb49b859 100644 --- a/src/modlunky2/ui/levels/shared/setrooms.py +++ b/src/modlunky2/ui/levels/shared/setrooms.py @@ -6,11 +6,13 @@ RoomCoords = namedtuple("RoomCoords", ["x", "y"]) MatchedSetroom = namedtuple("MatchedSetroom", ["name", "template", "coords"]) + @dataclass class BaseTemplateData: name: str template: str + class VANILLA_SETROOM_TYPE(Enum): NONE = "none" FRONT = "front" diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 4b02381c..e963a006 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -183,7 +183,6 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.template_draw_map = find_roommap(room_templates) self.canvas.grid_remove() - self.canvas = MultiCanvasContainer( self.editor_container, self.textures_dir, @@ -193,7 +192,7 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.canvas_click, self.canvas_shiftclick, intro_text="Select a level file to begin viewing", - vertical = True, + vertical=True, ) self.canvas.grid(row=0, column=0, columnspan=3, rowspan=2, sticky="news") self.canvas.show_intro() @@ -230,7 +229,9 @@ def __set_zoom(self, zoom): self.tile_image_map = {} self.redraw() - def __get_chunk_for_template_draw_item(self, template, template_index, map_index, row, column): + def __get_chunk_for_template_draw_item( + self, template, template_index, map_index, row, column + ): chunk_index = None if len(template.rooms) == 0: return None, None @@ -272,7 +273,9 @@ def __get_chunk_for_template_draw_item(self, template, template_index, map_index chunk = template.rooms[chunk_index] return chunk_index, chunk - def __get_template_draw_item(self, template, template_index, map_index, row, column): + def __get_template_draw_item( + self, template, template_index, map_index, row, column + ): chunk_index, chunk = self.__get_chunk_for_template_draw_item( template, template_index, map_index, row, column ) @@ -313,7 +316,9 @@ def change_template_at(self, map_index, row, col, template, template_index): template, overlapping_row, overlapping_column, - ) = self.template_item_at(map_index, row + row_offset, col + col_offset) + ) = self.template_item_at( + map_index, row + row_offset, col + col_offset + ) if template is not None and ( overlapping_row != row or overlapping_column != col ): @@ -335,10 +340,12 @@ def expand_to_width_if_necessary(room_map, width): row.append(None) expand_to_height_if_necessary( - self.template_draw_map[map_index].rooms, row + template_draw_item.height_in_rooms + self.template_draw_map[map_index].rooms, + row + template_draw_item.height_in_rooms, ) expand_to_width_if_necessary( - self.template_draw_map[map_index].rooms, col + template_draw_item.width_in_rooms + self.template_draw_map[map_index].rooms, + col + template_draw_item.width_in_rooms, ) for row_offset in range(template_draw_item.height_in_rooms): for col_offset in range(template_draw_item.width_in_rooms): @@ -796,8 +803,12 @@ def draw_canvas(self): height = len(draw_rooms) width = len(draw_rooms[0]) - self.canvas.configure_size(width * 10, height * 8, CanvasIndex(0, map_index)) - self.canvas.configure_size(width * 10, height * 8, CanvasIndex(1, map_index)) + self.canvas.configure_size( + width * 10, height * 8, CanvasIndex(0, map_index) + ) + self.canvas.configure_size( + width * 10, height * 8, CanvasIndex(1, map_index) + ) self.canvas.draw_background(self.lvl_biome, CanvasIndex(0, map_index)) self.canvas.draw_background(self.lvl_biome, CanvasIndex(1, map_index)) @@ -909,7 +920,9 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): ) def template_item_at(self, map_index, row, col): - for room_row_index, room_row in enumerate(self.template_draw_map[map_index].rooms): + for room_row_index, room_row in enumerate( + self.template_draw_map[map_index].rooms + ): if room_row_index > row: return None, None, None for room_column_index, template_draw_item in enumerate(room_row): diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 39d23386..a37db953 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -317,7 +317,9 @@ def select_template(self): if template_index == 0: self.clear_templates() self.on_clear_template( - self.current_template_map_index, self.current_template_row, self.current_template_column + self.current_template_map_index, + self.current_template_row, + self.current_template_column, ) else: self.on_select_template( @@ -330,17 +332,32 @@ def select_template(self): def select_room(self): room_index = self.room_combobox.current() self.on_select_room( - room_index, self.current_template_map_index, self.current_template_row, self.current_template_column + room_index, + self.current_template_map_index, + self.current_template_row, + self.current_template_column, ) def duplicate_room(self): - self.on_duplicate_room(self.current_template_map_index, self.current_template_row, self.current_template_column) + self.on_duplicate_room( + self.current_template_map_index, + self.current_template_row, + self.current_template_column, + ) def rename_room(self): - self.on_rename_room(self.current_template_map_index, self.current_template_row, self.current_template_column) + self.on_rename_room( + self.current_template_map_index, + self.current_template_row, + self.current_template_column, + ) def delete_room(self): - self.on_delete_room(self.current_template_map_index, self.current_template_row, self.current_template_column) + self.on_delete_room( + self.current_template_map_index, + self.current_template_row, + self.current_template_column, + ) def clear_templates(self): self.template_combobox["values"] = ["None"] @@ -394,7 +411,11 @@ def set_empty_cell(self, map_index, row, column): def flip_setting(self, setting, value): self.on_flip_setting( - setting, value, self.current_template_map_index, self.current_template_row, self.current_template_column + setting, + value, + self.current_template_map_index, + self.current_template_row, + self.current_template_column, ) def on_flip_ignore(self): @@ -652,15 +673,17 @@ def set_templates(self, room_map, templates): room_row_start = 0 if self.room_map is not None: for template_map in self.room_map: - for row_index in range(len(template_map.rooms) + 1): - self.room_type_frame.rowconfigure(room_row_start + row_index * 2, minsize=0) + self.room_type_frame.rowconfigure( + room_row_start + row_index * 2, minsize=0 + ) if row_index + room_row_start != 0: - self.room_type_frame.rowconfigure(room_row_start + row_index * 2 - 1, minsize=0) + self.room_type_frame.rowconfigure( + room_row_start + row_index * 2 - 1, minsize=0 + ) room_row_start += (len(template_map.rooms) + 1) * 2 - self.room_map = room_map self.templates = templates @@ -675,10 +698,14 @@ def set_templates(self, room_map, templates): ) if row_index != 0: self.room_type_frame.rowconfigure( - room_row_start + row_index * 2 - 1, minsize=self.room_view_padding + room_row_start + row_index * 2 - 1, + minsize=self.room_view_padding, ) elif room_row_start != 0: - self.room_type_frame.rowconfigure(room_row_start + row_index * 2 - 1, minsize=self.room_view_size) + self.room_type_frame.rowconfigure( + room_row_start + row_index * 2 - 1, + minsize=self.room_view_size, + ) room_row_start += (len(template_map.rooms) + 1) * 2 for button in self.room_buttons: @@ -712,15 +739,21 @@ def set_templates(self, room_map, templates): ) ) new_button.grid( - row=room_row_start + row_index * 2, column=col_index * 2, sticky="news" + row=room_row_start + row_index * 2, + column=col_index * 2, + sticky="news", ) if ( - map_index == self.room_options.current_template_map_index and - row_index == self.room_options.current_template_row - and col_index == self.room_options.current_template_column + map_index + == self.room_options.current_template_map_index + and row_index == self.room_options.current_template_row + and col_index + == self.room_options.current_template_column ): self.button_for_selected_empty_room = new_button - self.room_options.set_empty_cell(map_index, row_index, col_index) + self.room_options.set_empty_cell( + map_index, row_index, col_index + ) else: new_button = tk.Button( self.room_type_frame, @@ -741,8 +774,8 @@ def set_templates(self, room_map, templates): sticky="news", ) if ( - map_index == self.room_options.current_template_map_index and - row_index == self.room_options.current_template_row + map_index == self.room_options.current_template_map_index + and row_index == self.room_options.current_template_row and col_index == self.room_options.current_template_column ): self.button_for_selected_room = new_button @@ -755,7 +788,9 @@ def set_templates(self, room_map, templates): if len(template_row) < 10: edge_frame = tk.Frame(self.room_type_frame) edge_frame.grid( - row=room_row_start + row_index * 2, column=len(template_row) * 2, sticky="news" + row=room_row_start + row_index * 2, + column=len(template_row) * 2, + sticky="news", ) edge_frame.columnconfigure(0, weight=1) edge_frame.rowconfigure(0, weight=1) @@ -776,7 +811,9 @@ def set_templates(self, room_map, templates): ) edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + edge_frame.bind( + "", lambda _, eb=edge_button: eb.grid_remove() + ) self.edge_frames.append(edge_frame) rooms = template_map.rooms @@ -798,13 +835,15 @@ def set_templates(self, room_map, templates): edge_button.grid(row=0, column=0, sticky="news") edge_button.grid_remove() edge_button.configure( - command=lambda r=len(rooms), c=col, m=map_index: self.show_create_new_dialog( - m, r, c - ) + command=lambda r=len( + rooms + ), c=col, m=map_index: self.show_create_new_dialog(m, r, c) ) edge_frame.bind("", lambda _, eb=edge_button: eb.grid()) - edge_frame.bind("", lambda _, eb=edge_button: eb.grid_remove()) + edge_frame.bind( + "", lambda _, eb=edge_button: eb.grid_remove() + ) self.edge_frames.append(edge_frame) room_row_start += (len(template_map.rooms) + 1) * 2 self.highlight_selected_button() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py index c201ec87..c0b85392 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/room_map.py @@ -13,6 +13,7 @@ TemplateDrawItem, ) + @dataclass class RoomMap: name: str @@ -167,12 +168,11 @@ def set_room(room_map, x, y, room): olmecship_room = template_map.get("olmecship_room") if olmecship_room: - for i, room in enumerate(room_map[more_rooms_start - 1]): + for i, room in enumerate(path_map[more_rooms_start - 1]): if room is None: set_room(path_map, i, more_rooms_start - 1, olmecship_room) break - challenge_entrance = template_map.get("challenge_entrance") challenge_special = template_map.get("challenge_special") challenge_bottom = template_map.get("challenge_bottom") @@ -229,7 +229,6 @@ def set_room(room_map, x, y, room): if len(path_map) > 0: room_map.append(RoomMap("path", path_map)) - other_rooms_map = [] bigroom_side = template_map.get("machine_bigroom_side") @@ -294,11 +293,15 @@ def set_room(room_map, x, y, room): if bottom_room: if vertical_max_height < r + 1: vertical_max_height = r + 1 - set_room(other_rooms_map, vertical_room_column, more_rooms_start + r, bottom_room) + set_room( + other_rooms_map, vertical_room_column, more_rooms_start + r, bottom_room + ) if top_room is not None or bottom_room is not None: vertical_room_column += 1 - more_rooms_bottom = more_rooms_start + vertical_max_height - 1 + more_rooms_bottom = max( + more_rooms_start, more_rooms_start + vertical_max_height - 1 + ) other_rooms_to_add = [ "abzu_backdoor", @@ -363,7 +366,9 @@ def set_room(room_map, x, y, room): if not added_room: if len(other_rooms_map) > 0 and len(other_rooms_map[0]) < 3: - set_room(other_rooms_map, len(other_rooms_map[0]), more_rooms_start, room) + set_room( + other_rooms_map, len(other_rooms_map[0]), more_rooms_start, room + ) else: more_rooms_start = more_rooms_bottom + 1 more_rooms_bottom = more_rooms_start From 98eb764c577d417e0cf2a53cb473c6ae9982e0db Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 00:09:03 -0700 Subject: [PATCH 55/61] Give vanilla editor the logic of chosing default tiles from the custom editor instead of arbitrarily picking the last tile. --- .../vanilla_levels/vanilla_level_editor.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 76421f48..21c7dd32 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -432,6 +432,33 @@ def read_lvl_file(self, lvl): self.tile_palette_ref_in_use.append(tilecode_item) self.tile_palette_map[tilecode.value] = tilecode_item + # Populate the default tile code for left clicks. + if "1" in self.tile_palette_map: + # If there is a "1" tile code, guess it is a good default tile since it is often the floor. + tile = self.tile_palette_map["1"] + self.palette_panel.select_tile(tile[0], tile[2], True) + elif len(self.tile_palette_ref_in_use) > 0: + # If there is no "1" tile, just populate with the first tile. + tile = self.tile_palette_ref_in_use[0] + self.palette_panel.select_tile(tile[0], tile[2], True) + secondary_backup_index = 1 + + # Populate the default tile code for right clicks. + if "0" in self.tile_palette_map: + # If there is a "0" tile code, guess it is a good default secondary tile since it is often the empty tile. + tile = self.tile_palette_map["0"] + self.palette_panel.select_tile(tile[0], tile[2], False) + elif len(self.tile_palette_ref_in_use) > secondary_backup_index: + # If there is not a "0" tile code, populate with the second tile code if the + # primary tile code was populated from the first one. + tile = self.tile_palette_ref_in_use[secondary_backup_index] + self.palette_panel.select_tile(tile[0], tile[2], False) + elif len(self.tile_palette_ref_in_use) > 0: + # If there are only one tile code available, populate both right and + # left click with it. + tile = self.tile_palette_ref_in_use[0] + self.palette_panel.select_tile(tile[0], tile[2], False) + if level is None: return From 8716dce4b00c5e2e724963abcde4a7fa22cd59fd Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 00:27:01 -0700 Subject: [PATCH 56/61] Hide full level view tab --- src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 21c7dd32..043aed3b 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -270,7 +270,6 @@ def toggle_hide_grid(): # Level Editor Tab self.tab_control.add(self.editor_tab, text="Level Editor") self.tab_control.add(self.rules_tab, text="Rules") - self.tab_control.add(self.preview_tab, text="Full Level View") self.tab_control.add(self.multi_room_editor_tab, text="Full Level Editor") self.tab_control.add(self.variables_tab, text="Variables (Experimental)") From 930f3a2436fde3b9ec6df8a0751c00eb6e29208e Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 00:42:40 -0700 Subject: [PATCH 57/61] Stop losing room name's nullability. --- src/modlunky2/ui/levels/vanilla_levels/levels_tree.py | 8 ++++---- .../ui/levels/vanilla_levels/multi_room/options_panel.py | 4 ++-- .../ui/levels/vanilla_levels/vanilla_level_editor.py | 9 ++------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/modlunky2/ui/levels/vanilla_levels/levels_tree.py b/src/modlunky2/ui/levels/vanilla_levels/levels_tree.py index 1c48b824..7677aae2 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/levels_tree.py +++ b/src/modlunky2/ui/levels/vanilla_levels/levels_tree.py @@ -90,7 +90,7 @@ def duplicate(self): item_index = self.index(item_iid) parent_index = self.index(parent_iid) new_room = self.on_duplicate_room(parent_index, item_index) - self.insert(parent_iid, "end", text=new_room.name) + self.insert(parent_iid, "end", text=new_room.name or "room") def copy(self): item_iid = self.selection()[0] @@ -109,7 +109,7 @@ def paste(self): item_index = self.index(parent_iid) item_iid = parent_iid new_room = self.on_paste_room(item_index) - self.insert(item_iid, "end", text=new_room.name) + self.insert(item_iid, "end", text=new_room.name or "room") def delete_selected(self): item_iid = self.selection()[0] @@ -145,7 +145,7 @@ def add_room(self): return new_room = self.on_add_room(self.index(parent)) - self.insert(parent, "end", text=new_room.name) + self.insert(parent, "end", text=new_room.name or "room") def rename_dialog(self): item_iid = self.selection()[0] @@ -211,7 +211,7 @@ def set_rooms(self, rooms): room_display_name += " // " + room.comment entry = self.insert("", "end", text=room_display_name) for layout in room.rooms: - self.insert(entry, "end", text=layout.name) + self.insert(entry, "end", text=layout.name or "room") def get_selected_room(self): selection = self.selection() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index a37db953..a77dac1c 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -381,11 +381,11 @@ def set_current_template(self, template, map_index, row, column): self.configure_reverse_rooms_container() self.template_combobox.set(template.template.name) self.room_combobox["values"] = [ - room.name or "room " + (index + 1) + room.name or "room " + str(index + 1) for index, room in enumerate(template.template.rooms) ] + ["Create New"] self.room_combobox.set( - template.room_chunk.name or "room " + (template.room_index + 1) + template.room_chunk.name or "room " + str(template.room_index + 1) ) self.room_combobox.current(template.room_index) self.template_container.grid() diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 043aed3b..381a4be3 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -668,8 +668,6 @@ def changes_made(self): def convert_from_chunk(self, chunk): settings = list(map(lambda setting: setting, chunk.settings)) - i = 0 - def map_layer(layer): return list(map(lambda line: list(map(lambda tile: tile, line)), layer)) @@ -681,13 +679,10 @@ def map_layer(layer): ["0" for _ in range(len(row))] for row in foreground_tiles ] - room_name = "room" comment = str(chunk.comment).lstrip("/ ").strip() - if comment: - room_name = comment return RoomInstance( - str(room_name), settings, foreground_tiles, background_tiles + comment, settings, foreground_tiles, background_tiles ) def convert_to_chunk(self, room_instance): @@ -1186,7 +1181,7 @@ def map_layer(layer): return [[t for t in row] for row in layer] new_room = RoomInstance( - room_instance.name + " COPY", + (room_instance.name or "room") + " COPY", new_settings, map_layer(room_instance.front), map_layer(room_instance.back), From e1a6d8a83f5a752fad99b408505166bf334dff4a Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 23:26:27 -0700 Subject: [PATCH 58/61] Try to fix scroll bars not showing up on teeny baby windows. --- .../ui/levels/custom_levels/custom_level_editor.py | 2 ++ src/modlunky2/ui/levels/shared/multi_canvas_container.py | 5 +++++ .../vanilla_levels/multi_room/multi_room_editor_tab.py | 2 ++ .../ui/levels/vanilla_levels/vanilla_level_editor.py | 6 ++---- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py index 66163535..dd2d7554 100644 --- a/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py +++ b/src/modlunky2/ui/levels/custom_levels/custom_level_editor.py @@ -555,6 +555,8 @@ def draw_layer(canvas_index, tile_codes): for index, tileset in enumerate(self.tile_codes): draw_layer(CanvasIndex(index, 0), tileset) + self.canvas.update_scroll_region() + # Click event on a canvas for either left or right click to replace the tile at the cursor's position with # the selected tile. def canvas_click(self, canvas_index, row, column, is_primary): diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index f87e12bb..8e55b959 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -48,6 +48,7 @@ def __init__( scrollable_frame = tk.Frame(scrollable_canvas, bg="#343434") scrollable_frame.grid(row=0, column=0, sticky="nswe") + self.scrollable_frame = scrollable_frame width = scrollable_canvas.winfo_screenwidth() height = scrollable_canvas.winfo_screenheight() @@ -207,6 +208,10 @@ def switch_layer(): ) intro_label.place(relx=0.5, rely=0.5, anchor="center") + def update_scroll_region(self): + self.scrollable_canvas.update_idletasks() + self.scrollable_canvas.config(scrollregion=self.scrollable_frame.bbox("all")) + def _on_mousewheel(self, event, hbar, vbar, canvas): scroll_dir = None if event.num == 5 or event.delta == -120: diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index e963a006..f1862de8 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -919,6 +919,8 @@ def draw_chunk(canvas_index, chunk_start_x, chunk_start_y, tile_codes): room_column_index, ) + self.canvas.update_scroll_region() + def template_item_at(self, map_index, row, col): for room_row_index, room_row in enumerate( self.template_draw_map[map_index].rooms diff --git a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py index 381a4be3..24cd6546 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py +++ b/src/modlunky2/ui/levels/vanilla_levels/vanilla_level_editor.py @@ -681,9 +681,7 @@ def map_layer(layer): comment = str(chunk.comment).lstrip("/ ").strip() - return RoomInstance( - comment, settings, foreground_tiles, background_tiles - ) + return RoomInstance(comment, settings, foreground_tiles, background_tiles) def convert_to_chunk(self, room_instance): bg = [] @@ -1017,7 +1015,7 @@ def room_select(self, _event): # Loads room when click if not parent node. x_coord, y_coord, ) - + self.canvas.update_scroll_region() else: self.canvas.clear() self.canvas.hide_canvas(1, True) From 09f4b94cc78c3524b979d9acf589ab5f8b860cf2 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Sun, 17 Dec 2023 23:31:22 -0700 Subject: [PATCH 59/61] Try moving the canavas a bit after loading a level file or room. --- src/modlunky2/ui/levels/shared/multi_canvas_container.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 8e55b959..4bdac0c5 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -212,6 +212,9 @@ def update_scroll_region(self): self.scrollable_canvas.update_idletasks() self.scrollable_canvas.config(scrollregion=self.scrollable_frame.bbox("all")) + self.scrollable_canvas.xview_moveto(.5) + self.scrollable_canvas.yview_moveto(.2) + def _on_mousewheel(self, event, hbar, vbar, canvas): scroll_dir = None if event.num == 5 or event.delta == -120: From cc4911cabbf705534388f2c10a9a41777cbabf3b Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Mon, 18 Dec 2023 01:20:00 -0700 Subject: [PATCH 60/61] Save and load custom room map layouts. --- src/modlunky2/config.py | 23 +++- .../multi_room/multi_room_editor_tab.py | 54 ++++++-- .../multi_room/options_panel.py | 118 +++++++++++++++++- 3 files changed, 185 insertions(+), 10 deletions(-) diff --git a/src/modlunky2/config.py b/src/modlunky2/config.py index 30199f84..0731a4d9 100644 --- a/src/modlunky2/config.py +++ b/src/modlunky2/config.py @@ -7,7 +7,7 @@ import shutil import time from enum import Enum -from typing import List, Optional, TypeVar, Set +from typing import Dict, List, Optional, TypeVar, Set try: import winreg @@ -206,6 +206,21 @@ def level_sequence(cls): def vanilla(cls): return cls("Vanilla setroom [warning]", "setroom{y}-{x}", False) +@serialize(rename_all="kebabcase") +@deserialize(rename_all="kebabcase") +@dataclass +class CustomRoomMapSegment: + name: str + templates: List[List[str]] + + +@serialize(rename_all="kebabcase") +@deserialize(rename_all="kebabcase") +@dataclass +class CustomRoomMap: + name: str + segments: List[CustomRoomMapSegment] + @serialize(rename_all="kebabcase") @deserialize(rename_all="kebabcase") @@ -248,6 +263,12 @@ class Config: custom_level_editor_default_save_format: Optional[CustomLevelSaveFormat] = field( default=None, skip_if_default=True ) + custom_room_maps: Dict[str, List[CustomRoomMap]] = field( + default_factory=dict, skip_if_default=True + ) + default_custom_room_maps: Dict[str, int] = field( + default_factory=dict, skip_if_default=True + ) command_prefix: Optional[List[str]] = field(default=None, skip_if_default=True) api_port: int = field(default=9526) diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index f1862de8..0f5fdb20 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -18,6 +18,7 @@ from modlunky2.ui.levels.vanilla_levels.multi_room.room_map import ( find_roommap, get_template_draw_item, + RoomMap, ) from modlunky2.ui.levels.vanilla_levels.multi_room.template_draw_item import ( TemplateDrawItem, @@ -73,6 +74,7 @@ def __init__( self.tile_image_map = {} self.room_templates = [] self.template_draw_map = [] + self.default_draw_map = None self.reverse_layers = True self.zoom_level = zoom @@ -146,6 +148,7 @@ def toggle_panel_hidden(): self.canvas.hide_grid_lines, self.canvas.hide_room_lines, self.__update_zoom_internal, + self.use_roommap_at, self.change_template_at, self.clear_template_at, self.change_room_at, @@ -173,14 +176,36 @@ def image_for_tile_code(self, tile_code): self.tile_image_map[tile_name] = new_tile_image return new_tile_image - def open_lvl(self, lvl, biome, tile_palette_map, room_templates): - self.lvl = lvl - self.lvl_biome = biome - self.tile_palette_map = tile_palette_map - self.tile_image_map = {} - self.room_templates = room_templates + def use_roommap_at(self, index): + if self.lvl is None: + return + + def template_draw_map_for_roommap(room_map): + def get_template_draw_item_named(template_name): + if template_name is None: + return None + for index, template in enumerate(self.room_templates): + if template_name == template.name: + return get_template_draw_item(template, index) + + return None + + mappy = [] + for segment in room_map.segments: + mappy.append( + RoomMap( + segment.name, + [[get_template_draw_item_named(template_name) for template_name in row] for row in segment.templates] + ) + ) + return mappy + + room_maps = self.modlunky_config.custom_room_maps.get(self.lvl) + if index is None or index == -1 or index >= len(room_maps): + self.template_draw_map = self.default_draw_map + else: + self.template_draw_map = template_draw_map_for_roommap(room_maps[index]) - self.template_draw_map = find_roommap(room_templates) self.canvas.grid_remove() self.canvas = MultiCanvasContainer( @@ -200,9 +225,22 @@ def open_lvl(self, lvl, biome, tile_palette_map, room_templates): self.show_intro() self.options_panel.reset() - self.options_panel.set_templates(self.template_draw_map, room_templates) + self.options_panel.set_lvl(self.lvl) + self.options_panel.set_templates(self.template_draw_map, self.room_templates) self.draw_canvas() + def open_lvl(self, lvl, biome, tile_palette_map, room_templates): + self.lvl = lvl + self.lvl_biome = biome + self.tile_palette_map = tile_palette_map + self.tile_image_map = {} + self.room_templates = room_templates + + self.default_draw_map = find_roommap(room_templates) + # self.template_draw_map = find_roommap(room_templates) + + self.use_roommap_at(self.modlunky_config.default_custom_room_maps.get(self.lvl)) + def redraw(self): self.canvas.clear() self.show_intro() diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index a77dac1c..9aa470be 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -1,7 +1,7 @@ import tkinter as tk from tkinter import ttk -from modlunky2.config import Config +from modlunky2.config import Config, CustomRoomMap, CustomRoomMapSegment from modlunky2.levels.level_templates import TemplateSetting from modlunky2.ui.levels.vanilla_levels.multi_room.reversed_rooms import REVERSED_ROOMS from modlunky2.ui.widgets import PopupWindow, ScrollableFrameLegacy @@ -503,6 +503,7 @@ def __init__( on_update_hide_grid_lines, on_update_hide_room_lines, on_update_zoom_level, + on_select_layout, on_change_template_at, on_clear_template, on_select_room, @@ -520,6 +521,7 @@ def __init__( self.on_update_hide_grid_lines = on_update_hide_grid_lines self.on_update_hide_room_lines = on_update_hide_room_lines self.on_update_zoom_level = on_update_zoom_level + self.on_select_layout = on_select_layout self.on_change_template_at = on_change_template_at self.on_clear_template = on_clear_template self.on_select_room = on_select_room @@ -536,6 +538,7 @@ def __init__( self.room_map = [] self.templates = [] + self.lvl = None self.button_for_selected_room = None self.button_for_selected_empty_room = None @@ -618,6 +621,32 @@ def update_grid_size(_): settings_row += 1 + self.layout_frame = tk.Frame(self.scrollview.scrollable_frame) + self.layout_frame.grid(row=settings_row, column=0, sticky="news", padx=10, pady=10) + + self.layout_label = tk.Label(self.layout_frame, text="Layout:") + self.layout_label.grid(row=0, column=0, sticky="w") + + + self.layout_combobox = ttk.Combobox(self.layout_frame, height=25) + self.layout_combobox.grid(row=0, column=1, sticky="nsw", padx=(0, 10)) + self.layout_combobox["values"] = ["Default"] + self.layout_combobox.set("Default") + self.layout_combobox["state"] = "readonly" + self.layout_combobox.bind( + "<>", lambda _: self.select_layout() + ) + + self.layout_combobox.grid_remove() + self.layout_label.grid_remove() + + self.save_layout_button = tk.Button(self.layout_frame, text="Save layout", command=self.save_room_map) + self.save_layout_button.grid(row=0, column=2, sticky="w") + self.save_layout_button.grid_remove() + self.layout_frame.grid_remove() + + settings_row += 1 + self.room_type_frame = tk.Frame(self.scrollview.scrollable_frame) self.room_type_frame.grid( row=settings_row, column=0, sticky="news", padx=10, pady=10 @@ -652,18 +681,105 @@ def update_grid_size(_): self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() + + def save_room_map(self): + win = PopupWindow("Save Layout", self.modlunky_config) + + item_name = "" + + col1_lbl = ttk.Label(win, text="Name: ") + col1_ent = ttk.Entry(win) + col1_ent.insert(0, item_name) # Default to rooms current name + col1_lbl.grid(row=0, column=0, padx=2, pady=2, sticky="nse") + col1_ent.grid(row=0, column=1, padx=2, pady=2, sticky="news") + + def save_and_destroy(): + if col1_ent.get() == "": + return + segments = [] + for template_map in self.room_map: + segment = CustomRoomMapSegment( + template_map.name, + [[room.template.name if room else "" for room in row] for row in template_map.rooms] + ) + segments.append(segment) + room_map = CustomRoomMap(col1_ent.get(), segments) + level_room_maps = self.modlunky_config.custom_room_maps.get(self.lvl) + if level_room_maps is None: + level_room_maps = [] + level_room_maps.append(room_map) + self.modlunky_config.custom_room_maps[self.lvl] = level_room_maps + self.modlunky_config.default_custom_room_maps[self.lvl] = len(level_room_maps) - 1 + self.modlunky_config.save() + self.update_layouts() + + win.destroy() + + separator = ttk.Separator(win) + separator.grid(row=1, column=0, columnspan=2, pady=5, sticky="news") + + buttons = ttk.Frame(win) + buttons.grid(row=2, column=0, columnspan=2, sticky="news") + buttons.columnconfigure(0, weight=1) + buttons.columnconfigure(1, weight=1) + + ok_button = ttk.Button(buttons, text="Save", command=save_and_destroy) + ok_button.grid(row=0, column=0, pady=5, sticky="news") + + cancel_button = ttk.Button(buttons, text="Cancel", command=win.destroy) + cancel_button.grid(row=0, column=1, pady=5, sticky="news") + def update_room_map_template(self, template_index, map_index, row, column): template = self.templates[template_index] self.on_change_template_at(map_index, row, column, template, template_index) + self.layout_frame.grid() + self.save_layout_button.grid() def clear_template(self, map_index, row, column): self.on_clear_template(map_index, row, column) + self.layout_frame.grid() + self.save_layout_button.grid() def reset(self): self.button_for_selected_room = None self.button_for_selected_empty_room = None self.room_options.grid_remove() self.room_options.reset() + self.layout_frame.grid_remove() + self.save_layout_button.grid_remove() + + def select_layout(self): + selected_layout = self.layout_combobox.current() + if selected_layout is None: + selected_layout = 0 + + self.modlunky_config.default_custom_room_maps[self.lvl] = selected_layout - 1 + self.on_select_layout(selected_layout - 1) + self.modlunky_config.save() + + def update_layouts(self): + level_room_maps = self.modlunky_config.custom_room_maps.get(self.lvl) + if level_room_maps is not None and len(level_room_maps) > 0: + self.layout_combobox.grid() + self.layout_label.grid() + self.layout_frame.grid() + self.layout_combobox["values"] = ["Default"] + [map.name for map in level_room_maps] + default_layout = self.modlunky_config.default_custom_room_maps.get(self.lvl) + layout_index = default_layout + 1 if default_layout is not None else 0 + self.layout_combobox.current(layout_index) + self.layout_combobox.set(self.layout_combobox["values"][layout_index]) + else: + self.layout_combobox.grid_remove() + self.layout_label.grid_remove() + + def set_lvl(self, lvl): + self.lvl = lvl + self.layout_frame.grid_remove() + self.save_layout_button.grid_remove() + self.layout_combobox.grid_remove() + self.layout_label.grid_remove() + + self.update_layouts() def set_templates(self, room_map, templates): self.button_for_selected_room = None From bafd60632b837c3732f5eea5490401d59d9bc934 Mon Sep 17 00:00:00 2001 From: JayTheBusinessGoose Date: Mon, 18 Dec 2023 01:20:42 -0700 Subject: [PATCH 61/61] Formatter --- src/modlunky2/config.py | 1 + .../levels/shared/multi_canvas_container.py | 4 ++-- .../multi_room/multi_room_editor_tab.py | 8 ++++++- .../multi_room/options_panel.py | 23 +++++++++++++------ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/modlunky2/config.py b/src/modlunky2/config.py index 0731a4d9..bba6e803 100644 --- a/src/modlunky2/config.py +++ b/src/modlunky2/config.py @@ -206,6 +206,7 @@ def level_sequence(cls): def vanilla(cls): return cls("Vanilla setroom [warning]", "setroom{y}-{x}", False) + @serialize(rename_all="kebabcase") @deserialize(rename_all="kebabcase") @dataclass diff --git a/src/modlunky2/ui/levels/shared/multi_canvas_container.py b/src/modlunky2/ui/levels/shared/multi_canvas_container.py index 4bdac0c5..403985ab 100644 --- a/src/modlunky2/ui/levels/shared/multi_canvas_container.py +++ b/src/modlunky2/ui/levels/shared/multi_canvas_container.py @@ -212,8 +212,8 @@ def update_scroll_region(self): self.scrollable_canvas.update_idletasks() self.scrollable_canvas.config(scrollregion=self.scrollable_frame.bbox("all")) - self.scrollable_canvas.xview_moveto(.5) - self.scrollable_canvas.yview_moveto(.2) + self.scrollable_canvas.xview_moveto(0.5) + self.scrollable_canvas.yview_moveto(0.2) def _on_mousewheel(self, event, hbar, vbar, canvas): scroll_dir = None diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py index 0f5fdb20..fba7eefe 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/multi_room_editor_tab.py @@ -195,7 +195,13 @@ def get_template_draw_item_named(template_name): mappy.append( RoomMap( segment.name, - [[get_template_draw_item_named(template_name) for template_name in row] for row in segment.templates] + [ + [ + get_template_draw_item_named(template_name) + for template_name in row + ] + for row in segment.templates + ], ) ) return mappy diff --git a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py index 9aa470be..f3680acd 100644 --- a/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py +++ b/src/modlunky2/ui/levels/vanilla_levels/multi_room/options_panel.py @@ -622,12 +622,13 @@ def update_grid_size(_): settings_row += 1 self.layout_frame = tk.Frame(self.scrollview.scrollable_frame) - self.layout_frame.grid(row=settings_row, column=0, sticky="news", padx=10, pady=10) + self.layout_frame.grid( + row=settings_row, column=0, sticky="news", padx=10, pady=10 + ) self.layout_label = tk.Label(self.layout_frame, text="Layout:") self.layout_label.grid(row=0, column=0, sticky="w") - self.layout_combobox = ttk.Combobox(self.layout_frame, height=25) self.layout_combobox.grid(row=0, column=1, sticky="nsw", padx=(0, 10)) self.layout_combobox["values"] = ["Default"] @@ -640,7 +641,9 @@ def update_grid_size(_): self.layout_combobox.grid_remove() self.layout_label.grid_remove() - self.save_layout_button = tk.Button(self.layout_frame, text="Save layout", command=self.save_room_map) + self.save_layout_button = tk.Button( + self.layout_frame, text="Save layout", command=self.save_room_map + ) self.save_layout_button.grid(row=0, column=2, sticky="w") self.save_layout_button.grid_remove() self.layout_frame.grid_remove() @@ -681,7 +684,6 @@ def update_grid_size(_): self.room_options.grid(row=settings_row, column=0, sticky="news") self.room_options.grid_remove() - def save_room_map(self): win = PopupWindow("Save Layout", self.modlunky_config) @@ -700,7 +702,10 @@ def save_and_destroy(): for template_map in self.room_map: segment = CustomRoomMapSegment( template_map.name, - [[room.template.name if room else "" for room in row] for row in template_map.rooms] + [ + [room.template.name if room else "" for room in row] + for row in template_map.rooms + ], ) segments.append(segment) room_map = CustomRoomMap(col1_ent.get(), segments) @@ -709,7 +714,9 @@ def save_and_destroy(): level_room_maps = [] level_room_maps.append(room_map) self.modlunky_config.custom_room_maps[self.lvl] = level_room_maps - self.modlunky_config.default_custom_room_maps[self.lvl] = len(level_room_maps) - 1 + self.modlunky_config.default_custom_room_maps[self.lvl] = ( + len(level_room_maps) - 1 + ) self.modlunky_config.save() self.update_layouts() @@ -763,7 +770,9 @@ def update_layouts(self): self.layout_combobox.grid() self.layout_label.grid() self.layout_frame.grid() - self.layout_combobox["values"] = ["Default"] + [map.name for map in level_room_maps] + self.layout_combobox["values"] = ["Default"] + [ + map.name for map in level_room_maps + ] default_layout = self.modlunky_config.default_custom_room_maps.get(self.lvl) layout_index = default_layout + 1 if default_layout is not None else 0 self.layout_combobox.current(layout_index)