From 49c835325223f3a9574c554bb5bfe7bc54d6900d Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 18 Aug 2022 23:04:01 +0200 Subject: [PATCH] Slot is now a dataclass instead of a simple typehint (should now allow support for the abbreviated slot like LC, MMM, ...) --- assets/language/en.json | 3 +- assets/language/fr.json | 3 +- source/mkw/OriginalTrack.py | 90 +++++++++++++------------- source/mkw/Slot.py | 101 ++++++++++++++++++++++++++++++ source/mkw/Track/AbstractTrack.py | 17 ++--- source/mkw/Track/Arena.py | 25 ++++---- source/mkw/__init__.py | 1 - 7 files changed, 173 insertions(+), 67 deletions(-) create mode 100644 source/mkw/Slot.py diff --git a/assets/language/en.json b/assets/language/en.json index f318067..e2c14f5 100644 --- a/assets/language/en.json +++ b/assets/language/en.json @@ -95,6 +95,7 @@ "RAISED": "raised", "CANNOT_FIND_TOOL": "Can't find tool", "IN_TOOLS_DIRECTORY": "in the tools directory.", - "CANNOT_EXTRACT_A_DIRECTORY": "Can't extract a directory" + "CANNOT_EXTRACT_A_DIRECTORY": "Can't extract a directory", + "CANNOT_FIND_SLOT": "Can't find slot" } } \ No newline at end of file diff --git a/assets/language/fr.json b/assets/language/fr.json index c05dcb0..f5d2417 100644 --- a/assets/language/fr.json +++ b/assets/language/fr.json @@ -96,6 +96,7 @@ "RAISED": "à levé", "CANNOT_FIND_TOOL": "Impossible de trouver l'outil", "IN_TOOLS_DIRECTORY": "dans le dossier des outils.", - "CANNOT_EXTRACT_A_DIRECTORY": "Impossible d'extraire un dossier" + "CANNOT_EXTRACT_A_DIRECTORY": "Impossible d'extraire un dossier", + "CANNOT_FIND_SLOT": "Impossible de trouver le slot" } } \ No newline at end of file diff --git a/source/mkw/OriginalTrack.py b/source/mkw/OriginalTrack.py index bc6e90e..efc34e2 100644 --- a/source/mkw/OriginalTrack.py +++ b/source/mkw/OriginalTrack.py @@ -9,7 +9,7 @@ class OriginalTrackNotFound(Exception): super().__init__(_("CANNOT_FIND_ORIGINAL_TRACK", ' "', track_data, '" ')) -@dataclass(init=True, slots=True, frozen=True) +@dataclass(init=True, slots=True) class OriginalTrack: """ An object representing one of the original track / arena of the game @@ -17,64 +17,66 @@ class OriginalTrack: name: str slot: Slot - nickname: str + + def __post_init__(self): + if isinstance(self.slot, str): self.slot = Slot.get(normal=self.slot) all_original_tracks: list[OriginalTrack] = [ - OriginalTrack(name="beginner_course", slot="T11", nickname="LC"), - OriginalTrack(name="farm_course", slot="T12", nickname="MMM"), - OriginalTrack(name="kinoko_course", slot="T13", nickname="MG"), - OriginalTrack(name="factory_course", slot="T14", nickname="TF"), + OriginalTrack(name="beginner_course", slot=Slot.get(normal="T11")), + OriginalTrack(name="farm_course", slot="T12"), + OriginalTrack(name="kinoko_course", slot="T13"), + OriginalTrack(name="factory_course", slot="T14"), - OriginalTrack(name="castle_course", slot="T21", nickname="MC"), - OriginalTrack(name="shopping_course", slot="T22", nickname="CM"), - OriginalTrack(name="boardcross_course", slot="T23", nickname="DKS"), - OriginalTrack(name="truck_course", slot="T24", nickname="WGM"), + OriginalTrack(name="castle_course", slot="T21"), + OriginalTrack(name="shopping_course", slot="T22"), + OriginalTrack(name="boardcross_course", slot="T23"), + OriginalTrack(name="truck_course", slot="T24"), - OriginalTrack(name="senior_course", slot="T31", nickname="DC"), - OriginalTrack(name="water_course", slot="T32", nickname="KC"), - OriginalTrack(name="treehouse_course", slot="T33", nickname="MT"), - OriginalTrack(name="volcano_course", slot="T34", nickname="GV"), + OriginalTrack(name="senior_course", slot="T31"), + OriginalTrack(name="water_course", slot="T32"), + OriginalTrack(name="treehouse_course", slot="T33"), + OriginalTrack(name="volcano_course", slot="T34"), - OriginalTrack(name="desert_course", slot="T41", nickname="DDR"), - OriginalTrack(name="ridgehighway_course", slot="T42", nickname="MH"), - OriginalTrack(name="koopa_course", slot="T43", nickname="BC"), - OriginalTrack(name="rainbow_course", slot="T44", nickname="RR"), + OriginalTrack(name="desert_course", slot="T41"), + OriginalTrack(name="ridgehighway_course", slot="T42"), + OriginalTrack(name="koopa_course", slot="T43"), + OriginalTrack(name="rainbow_course", slot="T44"), # retro tracks - OriginalTrack(name="old_peach_gc", slot="T51", nickname="gPB"), - OriginalTrack(name="old_falls_ds", slot="T52", nickname="dYF"), - OriginalTrack(name="old_obake_sfc", slot="T53", nickname="sGV2"), - OriginalTrack(name="old_mario_64", slot="T54", nickname="nMR"), + OriginalTrack(name="old_peach_gc", slot="T51"), + OriginalTrack(name="old_falls_ds", slot="T52"), + OriginalTrack(name="old_obake_sfc", slot="T53"), + OriginalTrack(name="old_mario_64", slot="T54"), - OriginalTrack(name="old_sherbet_64", slot="T61", nickname="nSL"), - OriginalTrack(name="old_heyho_gba", slot="T62", nickname="gSGB"), - OriginalTrack(name="old_town_ds", slot="T63", nickname="dDS"), - OriginalTrack(name="old_waluigi_gc", slot="T64", nickname="gWS"), + OriginalTrack(name="old_sherbet_64", slot="T61"), + OriginalTrack(name="old_heyho_gba", slot="T62"), + OriginalTrack(name="old_town_ds", slot="T63"), + OriginalTrack(name="old_waluigi_gc", slot="T64"), - OriginalTrack(name="old_desert_ds", slot="T71", nickname="dDH"), - OriginalTrack(name="old_koopa_gba", slot="T72", nickname="gBC3"), - OriginalTrack(name="old_donkey_64", slot="T73", nickname="nDKJP"), - OriginalTrack(name="old_mario_gc", slot="T74", nickname="gMC"), + OriginalTrack(name="old_desert_ds", slot="T71"), + OriginalTrack(name="old_koopa_gba", slot="T72"), + OriginalTrack(name="old_donkey_64", slot="T73"), + OriginalTrack(name="old_mario_gc", slot="T74"), - OriginalTrack(name="old_mario_sfc", slot="T81", nickname="sMC3"), - OriginalTrack(name="old_garden_ds", slot="T82", nickname="dPG"), - OriginalTrack(name="old_donkey_gc", slot="T83", nickname="gDKM"), - OriginalTrack(name="old_koopa_64", slot="T84", nickname="nBC"), + OriginalTrack(name="old_mario_sfc", slot="T81"), + OriginalTrack(name="old_garden_ds", slot="T82"), + OriginalTrack(name="old_donkey_gc", slot="T83"), + OriginalTrack(name="old_koopa_64", slot="T84"), # wii arena - OriginalTrack(name="block_battle", slot="A11", nickname="aBP"), - OriginalTrack(name="venice_battle", slot="A12", nickname="aDP"), - OriginalTrack(name="skate_battle", slot="A13", nickname="aFS"), - OriginalTrack(name="casino_battle", slot="A14", nickname="aCCW"), - OriginalTrack(name="sand_battle", slot="A15", nickname="aTD"), + OriginalTrack(name="block_battle", slot="A11"), + OriginalTrack(name="venice_battle", slot="A12"), + OriginalTrack(name="skate_battle", slot="A13"), + OriginalTrack(name="casino_battle", slot="A14"), + OriginalTrack(name="sand_battle", slot="A15"), # retro arena - OriginalTrack(name="old_battle4_sfc", slot="A21", nickname="asBC4"), - OriginalTrack(name="old_battle3_gba", slot="A22", nickname="agBC3"), - OriginalTrack(name="old_matenro_64", slot="A23", nickname="anSS"), - OriginalTrack(name="old_CookieLand_gc", slot="A24", nickname="agCL"), - OriginalTrack(name="old_House_ds", slot="A25", nickname="adTH"), + OriginalTrack(name="old_battle4_sfc", slot="A21"), + OriginalTrack(name="old_battle3_gba", slot="A22"), + OriginalTrack(name="old_matenro_64", slot="A23"), + OriginalTrack(name="old_CookieLand_gc", slot="A24"), + OriginalTrack(name="old_House_ds", slot="A25"), ] diff --git a/source/mkw/Slot.py b/source/mkw/Slot.py new file mode 100644 index 0000000..a75c413 --- /dev/null +++ b/source/mkw/Slot.py @@ -0,0 +1,101 @@ +from dataclasses import dataclass + + +class SlotNotFound(Exception): + def __init__(self, slot_data: any): + super().__init__(_("CANNOT_FIND_SLOT", ' "', slot_data, '" ')) + + +@dataclass(init=True, slots=True, frozen=True, repr=True) +class Slot: + """ + represent a game slot (arena, ...) + """ + + normal: str # T11, T12, ... + abbreviation: str # LC, MMM, ... + + def __str__(self) -> str: return self.normal + def __eq__(self, other) -> bool: return any(getattr(self, key) == other for key in self.__slots__) + + +all_slots: list[Slot] = [ + Slot(normal="T11", abbreviation="LC"), + Slot(normal="T12", abbreviation="MMM"), + Slot(normal="T13", abbreviation="MG"), + Slot(normal="T14", abbreviation="TF"), + + Slot(normal="T21", abbreviation="MC"), + Slot(normal="T22", abbreviation="CM"), + Slot(normal="T23", abbreviation="DKS"), + Slot(normal="T24", abbreviation="WGM"), + + Slot(normal="T31", abbreviation="DC"), + Slot(normal="T32", abbreviation="KC"), + Slot(normal="T33", abbreviation="MT"), + Slot(normal="T34", abbreviation="GV"), + + Slot(normal="T41", abbreviation="DDR"), + Slot(normal="T42", abbreviation="MH"), + Slot(normal="T43", abbreviation="BC"), + Slot(normal="T44", abbreviation="RR"), + + # retro tracks + Slot(normal="T51", abbreviation="gPB"), + Slot(normal="T52", abbreviation="dYF"), + Slot(normal="T53", abbreviation="sGV2"), + Slot(normal="T54", abbreviation="nMR"), + + Slot(normal="T61", abbreviation="nSL"), + Slot(normal="T62", abbreviation="gSGB"), + Slot(normal="T63", abbreviation="dDS"), + Slot(normal="T64", abbreviation="gWS"), + + Slot(normal="T71", abbreviation="dDH"), + Slot(normal="T72", abbreviation="gBC3"), + Slot(normal="T73", abbreviation="nDKJP"), + Slot(normal="T74", abbreviation="gMC"), + + Slot(normal="T81", abbreviation="sMC3"), + Slot(normal="T82", abbreviation="dPG"), + Slot(normal="T83", abbreviation="gDKM"), + Slot(normal="T84", abbreviation="nBC"), + + # wii arena + Slot(normal="A11", abbreviation="aBP"), + Slot(normal="A12", abbreviation="aDP"), + Slot(normal="A13", abbreviation="aFS"), + Slot(normal="A14", abbreviation="aCCW"), + Slot(normal="A15", abbreviation="aTD"), + + # retro arena + Slot(normal="A21", abbreviation="asBC4"), + Slot(normal="A22", abbreviation="agBC3"), + Slot(normal="A23", abbreviation="anSS"), + Slot(normal="A24", abbreviation="agCL"), + Slot(normal="A25", abbreviation="adTH"), +] + + +def get(**slot_datas) -> Slot: + """ + Get a original slot object from keys and its value + :param slot_datas: dictionary of track key and their value + :return: the corresponding slot + """ + try: + return next(filter( + lambda slot: all(getattr(slot, key) == value for key, value in slot_datas.items()), + all_slots + )) + except StopIteration: raise SlotNotFound(slot_datas) + + +def find(value) -> Slot: + """ + Return a slot from any value of any key. + :param value: the value used to search the slot + :return: the corresponding slot + """ + try: return next(filter(lambda slot: slot == value, all_slots)) + except StopIteration: raise SlotNotFound(value) diff --git a/source/mkw/Track/AbstractTrack.py b/source/mkw/Track/AbstractTrack.py index 206b1cc..c2a081e 100644 --- a/source/mkw/Track/AbstractTrack.py +++ b/source/mkw/Track/AbstractTrack.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from typing import Generator, TYPE_CHECKING -from source.mkw import Slot, Tag, ModConfig +from source.mkw import Tag, ModConfig, Slot from source.translation import translate as _ if TYPE_CHECKING: @@ -14,14 +14,15 @@ class TrackForbiddenCustomAttribute(Exception): class AbstractTrack(ABC): - music: Slot - special: Slot + music: Slot.Slot + special: Slot.Slot tags: list[Tag] weight: int - def __init__(self, music: Slot = "T11", special: Slot = "T11", tags: list[Tag] = None, weight: int = 1, **kwargs): - self.music = music - self.special = special + def __init__(self, music: Slot.Slot = "T11", special: Slot.Slot = "T11", + tags: list[Tag] = None, weight: int = 1, **kwargs): + self.music = Slot.find(music) + self.special = Slot.find(special) self.tags = tags if tags is not None else [] self.weight = weight @@ -87,8 +88,8 @@ class AbstractTrack(ABC): return ( f'{category} ' # category (is the track hidden, visible, an arena, ...) - f'{self.music}; ' # music - f'{self.special}; ' # property of the tracks + f'{self.music.normal}; ' # music + f'{self.special.normal}; ' # property of the tracks f'{flags:#04x}; ' # lecode flags f'{filename!r}; ' # filename f'{name!r}; ' # name of the track in the menu diff --git a/source/mkw/Track/Arena.py b/source/mkw/Track/Arena.py index 1dc91f7..03affd3 100644 --- a/source/mkw/Track/Arena.py +++ b/source/mkw/Track/Arena.py @@ -15,15 +15,16 @@ class ArenaForbiddenCustomAttribute(Exception): class Arena(RealArenaTrack): - slot: Slot - music: Slot - special: Slot + slot: Slot.Slot + music: Slot.Slot + special: Slot.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 + def __init__(self, slot: Slot.Slot, music: Slot.Slot = None, special: Slot.Slot = None, + tags: list[Tag] = None, **kwargs): + self.slot = Slot.find(slot) + self.music = Slot.find(music if music is not None else slot) + self.special = Slot.find(special if special is not None else slot) self.tags = tags if tags is not None else [] # others not mandatory attributes @@ -48,20 +49,20 @@ class Arena(RealArenaTrack): """ name: str = self.repr_format(mod_config=mod_config, template=template) - filename = self.get_filename(mod_config=mod_config) + filename: str = 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'{self.music.normal}; ' # music + f'{self.slot.normal}; ' # 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" + f"{self.slot.normal} " + f"{self.special.normal}\n" ) ) diff --git a/source/mkw/__init__.py b/source/mkw/__init__.py index 2534beb..c5d1a3f 100644 --- a/source/mkw/__init__.py +++ b/source/mkw/__init__.py @@ -1,2 +1 @@ Tag = str -Slot = str