From a51d6f217352334729dd9b2642d4171fb0e8a17f Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sat, 13 Aug 2022 12:16:37 +0200 Subject: [PATCH] implemented Arena (game text are missing) --- source/gui/preview/track_formatting.py | 2 +- source/gui/preview/track_selecting.py | 4 +- source/gui/preview/track_sorting.py | 2 +- source/mkw/Arena.py | 0 source/mkw/ModConfig.py | 40 ++++++++++++----- source/mkw/Track/AbstractTrack.py | 12 ------ source/mkw/Track/Arena.py | 60 ++++++++++++++++++++++++++ source/mkw/Track/CustomTrack.py | 17 ++------ source/mkw/Track/RealArenaTrack.py | 31 +++++++++++++ source/mkw/{ => Track}/TrackGroup.py | 0 source/mkw/Track/__init__.py | 2 + 11 files changed, 129 insertions(+), 41 deletions(-) delete mode 100644 source/mkw/Arena.py create mode 100644 source/mkw/Track/Arena.py create mode 100644 source/mkw/Track/RealArenaTrack.py rename source/mkw/{ => Track}/TrackGroup.py (100%) diff --git a/source/gui/preview/track_formatting.py b/source/gui/preview/track_formatting.py index 5d63a06..c27ab8f 100644 --- a/source/gui/preview/track_formatting.py +++ b/source/gui/preview/track_formatting.py @@ -49,7 +49,7 @@ class Window(AbstractPreviewWindow): self.text_track_format.delete(1.0, tkinter.END) # insert all the tracks representation - for track in self.mod_config.get_all_tracks(ignore_filter=True): + for track in self.mod_config.get_all_arenas_tracks(ignore_filter=True): try: track_repr = track.repr_format( self.mod_config, self.entry_template_input.get() diff --git a/source/gui/preview/track_selecting.py b/source/gui/preview/track_selecting.py index bc0982b..ee60e2d 100644 --- a/source/gui/preview/track_selecting.py +++ b/source/gui/preview/track_selecting.py @@ -65,7 +65,7 @@ class Window(AbstractPreviewWindow): self.text_track_format.delete(1.0, tkinter.END) # insert all the tracks representation - for track in self.mod_config.get_all_tracks(ignore_filter=True): + for track in self.mod_config.get_all_arenas_tracks(ignore_filter=True): self.text_track_format.insert(tkinter.END, f"{track}\n") self.text_track_format.configure(state=tkinter.DISABLED) @@ -83,7 +83,7 @@ class Window(AbstractPreviewWindow): return_lambda=True, lambda_args=["track"] ) - for track in self.mod_config.get_all_tracks(ignore_filter=True): + for track in self.mod_config.get_all_arenas_tracks(ignore_filter=True): value: bool = template_func(track) is True self.text_track_select.insert(tkinter.END, f"{value}\n") diff --git a/source/gui/preview/track_sorting.py b/source/gui/preview/track_sorting.py index 0930d90..3215060 100644 --- a/source/gui/preview/track_sorting.py +++ b/source/gui/preview/track_sorting.py @@ -49,7 +49,7 @@ class Window(AbstractPreviewWindow): template = self.entry_template_input.get() # insert all the tracks representation - for track in self.mod_config.get_all_tracks( + for track in self.mod_config.get_all_arenas_tracks( ignore_filter=True, sorting_template=template if template else None ): diff --git a/source/mkw/Arena.py b/source/mkw/Arena.py deleted file mode 100644 index e69de29..0000000 diff --git a/source/mkw/ModConfig.py b/source/mkw/ModConfig.py index 56182c3..2df1bda 100644 --- a/source/mkw/ModConfig.py +++ b/source/mkw/ModConfig.py @@ -9,7 +9,7 @@ from source.mkw import Tag from source.mkw.Cup import Cup from source.mkw.MKWColor import bmg_color_text, bmg_color_raw from source.mkw.ModSettings import AbstractModSettings -from source.mkw.Track import CustomTrack, DefaultTrack +from source.mkw.Track import CustomTrack, DefaultTrack, Arena import json from source.mkw.OriginalTrack import OriginalTrack @@ -68,7 +68,7 @@ class ModConfig: Representation of a mod """ - __slots__ = ("name", "path", "nickname", "variant", "_tracks", "version", + __slots__ = ("name", "path", "nickname", "variant", "_tracks", "arenas", "version", "original_track_prefix", "swap_original_order", "keep_original_track", "enable_random_cup", "tags_cups", "track_file_template", "multiplayer_disable_if", "macros", "messages", "global_settings", @@ -81,7 +81,7 @@ class ModConfig: track_file_template: str = None, multiplayer_disable_if: str = None, macros: dict[str, str] = None, messages: dict[str, dict[str, str]] = None, global_settings: dict[str, dict[str, str]] = None, specific_settings: dict[str, dict[str, str]] = None, lpar_template: str = None, - tags_templates: dict[str, str] = None): + tags_templates: dict[str, str] = None, arenas: list["Arena"] = None): self.path = Path(path) self.macros: dict = macros if macros is not None else {} @@ -109,6 +109,8 @@ class ModConfig: self.multiplayer_disable_if: str = multiplayer_disable_if if multiplayer_disable_if is not None else "False" self.lpar_template: str = lpar_template if lpar_template is not None else "normal.lpar" + self.arenas: list["Arena"] = arenas if arenas is not None else [] + self.original_track_prefix: bool = original_track_prefix if original_track_prefix is not None else True self.swap_original_order: bool = swap_original_order if swap_original_order is not None else True self.keep_original_track: bool = keep_original_track if keep_original_track is not None else True @@ -133,7 +135,7 @@ class ModConfig: kwargs = { attr: config_dict.get(attr) for attr in cls.__slots__ - if attr not in ["name", "_tracks", "tracks", "path", "macros", "messages"] + if attr not in ["name", "_tracks", "tracks", "arenas", "path", "macros", "messages"] # these keys are treated after or are reserved } @@ -144,6 +146,7 @@ class ModConfig: **kwargs, tracks=[CustomTrack.from_dict(track) for track in config_dict.get("tracks", [])], + arenas=[Arena.from_dict(arena) for arena in config_dict.get("arenas", [])], macros=macros, messages=messages, ) @@ -173,12 +176,12 @@ class ModConfig: :return: the modconfig environment """ return { - "mod_config": self, - "bmg_color_raw": bmg_color_raw, - "bmg_color_text": bmg_color_text - } | ( - base_env if base_env is not None else {} - ) + "mod_config": self, + "bmg_color_raw": bmg_color_raw, + "bmg_color_text": bmg_color_text + } | ( + base_env if base_env is not None else {} + ) def safe_eval(self, *args, env: dict[str, any] = None, **kwargs) -> any: """ @@ -201,6 +204,13 @@ class ModConfig: """ return self.path.parent + def get_all_arenas_tracks(self, *args, **kwargs) -> Generator["CustomTrack", None, None]: + """ + Same as get_all_tracks, but arenas are included + """ + yield from self.get_all_tracks(*args, **kwargs) + yield from self.arenas + def get_all_tracks(self, *args, **kwargs) -> Generator["CustomTrack", None, None]: """ Same as get_tracks, but track group are divided into subtracks @@ -325,6 +335,14 @@ class ModConfig: # get all the cup ctfile, use "-" for the template since the track's name are not used here ctfile += cup.get_ctfile(mod_config=self, template=template) + ctfile_override_property = "[SETUP-ARENA]\n" + for arena in self.arenas: + arena_definition, arena_override_property = arena.get_ctfile(mod_config=self, template=template) + ctfile += arena_definition + ctfile_override_property += arena_override_property + + ctfile += ctfile_override_property + return ctfile def get_base_cticons(self) -> Generator[Image.Image, None, None]: @@ -416,7 +434,7 @@ class ModConfig: return_lambda=True, lambda_args=["track"] ) - for track in self.get_all_tracks(): + for track in self.get_all_arenas_tracks(): track_file: Path = next( track_directory.rglob(f"{track.repr_format(self, self.track_file_template)}.*") ) diff --git a/source/mkw/Track/AbstractTrack.py b/source/mkw/Track/AbstractTrack.py index e7f234e..cbaf168 100644 --- a/source/mkw/Track/AbstractTrack.py +++ b/source/mkw/Track/AbstractTrack.py @@ -38,18 +38,6 @@ class AbstractTrack(ABC): for _ in range(self.weight): yield self - def get_tag_template(self, mod_config: "ModConfig", template_name: str, default: any = None) -> any: - """ - Return the tag template found in templates. If not found, return default - :param mod_config: mod configuration - :param template_name: name of the template of the tags - :param default: default value if no tag template is found - :return: formatted representation of the tag - """ - for tag in filter(lambda tag: tag in mod_config.tags_templates[template_name], self.tags): - return mod_config.multiple_safe_eval(mod_config.tags_templates[template_name][tag], env={"tag": tag}) - return default - @abstractmethod def repr_format(self, mod_config: "ModConfig", template: str) -> str: """ diff --git a/source/mkw/Track/Arena.py b/source/mkw/Track/Arena.py new file mode 100644 index 0000000..18f69a8 --- /dev/null +++ b/source/mkw/Track/Arena.py @@ -0,0 +1,60 @@ +from source.mkw import Slot, Tag +from source.mkw.Track.RealArenaTrack import RealArenaTrack + + +class ArenaForbiddenCustomAttribute(Exception): + def __init__(self, attribute_name: str): + super().__init__(f"Forbidden arena attribute : {attribute_name!r}") + + +class Arena(RealArenaTrack): + slot: Slot + music: Slot + special: Slot + tags: list[Tag] + + def __init__(self, slot: Slot, music: Slot = None, special: Slot = None, tags: list[Tag] = None, **kwargs): + self.slot = slot + self.music = music if music is not None else slot + self.special = special if special is not None else slot + self.tags = tags if tags is not None else [] + + # others not mandatory attributes + for key, value in kwargs.items(): + # if the attribute start with __, this is a magic attribute, and it should not be modified + if "__" in key or hasattr(self, key): raise ArenaForbiddenCustomAttribute(key) + setattr(self, key, value) + + def __repr__(self): + return f"<{self.__class__.__name__} name={getattr(self, 'name', '/')} tags={getattr(self, 'tags', '/')}>" + + @classmethod + def from_dict(cls, arena_dict: dict[str, any]) -> "Arena": + return cls(**arena_dict) + + def get_ctfile(self, mod_config: "ModConfig", template: str) -> (str, str): + """ + Return the ctfile for the arena and the redefinition of the slot property + :param mod_config: the mod_config object + :param template: the template of the track name + :return: the ctfile for the arena and the redefinition of the slot property + """ + + name: str = self.repr_format(mod_config=mod_config, template=template) + filename = self.get_filename(mod_config=mod_config) + + return ( + ( + f'A ' # category (A for arena) + f'{self.music}; ' # music + f'{self.slot}; ' # slot of the arena + f'0x00; ' # lecode flag + f'{filename!r}; ' # filename + f'{name!r}; ' # name of the track in the menu + f'{filename!r}\n' # unique identifier for each track + ), + ( + f"{self.slot} " + f"{self.special}\n" + ) + ) diff --git a/source/mkw/Track/CustomTrack.py b/source/mkw/Track/CustomTrack.py index f2c68cc..ef39caa 100644 --- a/source/mkw/Track/CustomTrack.py +++ b/source/mkw/Track/CustomTrack.py @@ -1,9 +1,10 @@ from source.mkw.Track.AbstractTrack import AbstractTrack +from source.mkw.Track.RealArenaTrack import RealArenaTrack ModConfig: any -class CustomTrack(AbstractTrack): +class CustomTrack(RealArenaTrack, AbstractTrack): """ Represent a custom track """ @@ -18,21 +19,9 @@ class CustomTrack(AbstractTrack): :return: Track """ if "group" in track_dict: - from source.mkw.TrackGroup import TrackGroup + from source.mkw.Track.TrackGroup import TrackGroup return TrackGroup.from_dict(track_dict) return cls(**track_dict) - def repr_format(self, mod_config: "ModConfig", template: str) -> str: - return mod_config.multiple_safe_eval( - template, - env={ - "track": self, - "get_tag_template": lambda *args, **kwargs: self.get_tag_template(mod_config, *args, **kwargs) - } - ) - - def get_filename(self, mod_config: "ModConfig") -> str: - return self.repr_format(mod_config=mod_config, template=mod_config.track_file_template) - def is_new(self, mod_config: "ModConfig") -> bool: return mod_config.safe_eval(mod_config.global_settings["replace_random_new"].value, env={"track": self}) is True diff --git a/source/mkw/Track/RealArenaTrack.py b/source/mkw/Track/RealArenaTrack.py new file mode 100644 index 0000000..dab527a --- /dev/null +++ b/source/mkw/Track/RealArenaTrack.py @@ -0,0 +1,31 @@ +class RealArenaTrack: + """ + class shared between all arena and track class that represent a "real" track or arena + (For example, DefaultTrack is not considered a real track class) + """ + + tags: list + + def get_tag_template(self, mod_config: "ModConfig", template_name: str, default: any = None) -> any: + """ + Return the tag template found in templates. If not found, return default + :param mod_config: mod configuration + :param template_name: name of the template of the tags + :param default: default value if no tag template is found + :return: formatted representation of the tag + """ + for tag in filter(lambda tag: tag in mod_config.tags_templates[template_name], self.tags): + return mod_config.multiple_safe_eval(mod_config.tags_templates[template_name][tag], env={"tag": tag}) + return default + + def repr_format(self, mod_config: "ModConfig", template: str) -> str: + return mod_config.multiple_safe_eval( + template, + env={ + "track": self, + "get_tag_template": lambda *args, **kwargs: self.get_tag_template(mod_config, *args, **kwargs) + } + ) + + def get_filename(self, mod_config: "ModConfig") -> str: + return self.repr_format(mod_config=mod_config, template=mod_config.track_file_template) diff --git a/source/mkw/TrackGroup.py b/source/mkw/Track/TrackGroup.py similarity index 100% rename from source/mkw/TrackGroup.py rename to source/mkw/Track/TrackGroup.py diff --git a/source/mkw/Track/__init__.py b/source/mkw/Track/__init__.py index 3d36e8b..f07ec47 100644 --- a/source/mkw/Track/__init__.py +++ b/source/mkw/Track/__init__.py @@ -1,3 +1,5 @@ from source.mkw.Track.CustomTrack import CustomTrack from source.mkw.Track.DefaultTrack import DefaultTrack from source.mkw.Track.AbstractTrack import AbstractTrack +from source.mkw.Track.TrackGroup import TrackGroup +from source.mkw.Track.Arena import Arena