diff --git a/source/CT_Config.py b/source/CT_Config.py new file mode 100644 index 0000000..cbe7768 --- /dev/null +++ b/source/CT_Config.py @@ -0,0 +1,87 @@ +from .Cup import * +import math +from PIL import Image, ImageFont, ImageDraw +import os + + +def get_cup_icon(i): + if os.path.exists(f"./file/cup_icon/{id}.png"): + cup_icon = Image.open(f"./file/cup_icon/{id}.png").resize((128, 128)) + + else: + cup_icon = Image.new("RGBA", (128, 128)) + draw = ImageDraw.Draw(cup_icon) + font = ImageFont.truetype("./file/SuperMario256.ttf", 90) + draw.text((4 - 2, 4 - 2), "CT", (0, 0, 0), font=font) + draw.text((4 + 2, 4 - 2), "CT", (0, 0, 0), font=font) + draw.text((4 - 2, 4 + 2), "CT", (0, 0, 0), font=font) + draw.text((4 + 2, 4 + 2), "CT", (0, 0, 0), font=font) + draw.text((4, 4), "CT", (255, 165, 0), font=font) + + font = ImageFont.truetype("./file/SuperMario256.ttf", 60) + draw.text((5 - 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # i-10 because first 8 cup are not + draw.text((5 + 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # counted as new, random cup, + draw.text((5 - 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) # left and right arrow + draw.text((5 + 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) + + draw.text((5, 80), "%03i" % (i - 10), (255, 165, 0), font=font) + return cup_icon + + +class CT_Config: + def __init__(self, version): + self.version = version + self.ordered_cups = [] + self.unordered_tracks = [] + self.all_version: set = {version} + + def add_ordered_cup(self, cup: Cup): + self.ordered_cups.append(cup) + for track in cup.get_tracks(): + self.all_version.add(track.since_version) + + def add_unordered_track(self, track: Track): + self.unordered_tracks.append(track) + self.all_version.add(track.since_version) + + def get_tracks(self): + """ + :return: all tracks from the CT_Config + """ + tracks = [] + for cup in self.ordered_cups: + tracks.extend(*cup.get_tracks()) + tracks.extend(self.unordered_tracks) + + return tracks + + def search_tracks(self, **kwargs): + tracks = self.get_tracks() + for keyword, value in kwargs.items(): + filter(lambda track: getattr(track, keyword) == value, tracks) + + def get_total_tracks_count(self): + return (len(self.ordered_cups) * 4) + len(self.unordered_tracks) + + def create_ctfile(self): + pass + + def get_cticon(self): + """ + get all cup icon into a single image + :return: ct_icon image + """ + CT_ICON_WIDTH = 128 + icon_files = ["left", "right"] + + total_cup_count = math.ceil(self.get_total_tracks_count() / 4) + ct_icon = Image.new("RGBA", (CT_ICON_WIDTH, CT_ICON_WIDTH * (total_cup_count + 2))) # +2 because of left and right arrow + + icon_files.extend([cup.id for cup in self.ordered_cups]) # adding ordered cup id + icon_files.extend(["_"] * ((len(self.unordered_tracks) // 4) + 1)) # creating unordered track icon + + for i, id in enumerate(icon_files): + cup_icon = get_cup_icon(i) + ct_icon.paste(cup_icon, (0, i * CT_ICON_WIDTH)) + + return ct_icon #ct_icon.save("./file/ct_icons.tpl.png") diff --git a/source/Cup.py b/source/Cup.py new file mode 100644 index 0000000..90744c8 --- /dev/null +++ b/source/Cup.py @@ -0,0 +1,26 @@ +from .Track import * +from PIL import Image +from .patch_ct_icon import get_cup_icon + + +class Cup: + def __init__(self, name: str, id: int, + track1: Track = EMPTY_TRACK, + track2: Track = EMPTY_TRACK, + track3: Track = EMPTY_TRACK, + track4: Track = EMPTY_TRACK, + icon: Image = None): + + self.name = name + self.track1 = track1 + self.track2 = track2 + self.track3 = track3 + self.track4 = track4 + self.icon = icon if icon else create_cup_icon(id) + self.id = id # cup number + + def get_ctfile_cup(self): + pass + + def get_tracks(self): + return self.track1, self.track2, self.track3, self.track4 diff --git a/source/Game.py b/source/Game.py new file mode 100644 index 0000000..fcf8e7c --- /dev/null +++ b/source/Game.py @@ -0,0 +1,20 @@ +from .definition import region_ID + + +class Game: + def __init__(self, path: str, region: str = "PAL"): + self.path = path + self.region_ID = region_ID[region] + self.region = region + + def extract_game(self): + pass + + def install_mod(self): + pass + + def convert_to(self, format: str = "FST"): + """ + :param format: game format (ISO, WBFS, ...) + :return: converted game path + """ \ No newline at end of file diff --git a/source/Track.py b/source/Track.py new file mode 100644 index 0000000..b0a99d7 --- /dev/null +++ b/source/Track.py @@ -0,0 +1,73 @@ +from .definition import * +import subprocess +import source.wszst + + +class Track: + def __init__(self, name: str, file_wu8: str = None, file_szs: str = None, prefix: str = None, suffix: str = None, + author="Nintendo", special="T11", music="T11", new=True, sha1: str = None, since_version: str = None, + score: int = 0, warning: int = 0, note: str = ""): + + self.name = name # Track name + self.prefix = prefix # Prefix, often used for game or original console like Wii U, DS, ... + self.suffix = suffix # Suffix, often used for variety like Boost, Night, ... + self.author = author # Track author + self.sha1 = sha1 # Track sha1 from wszst SHA1 + self.special = special # Special slot of the track + self.music = music # Music of the track + self.new = new # Is the track new + self.since_version = since_version # Since which version is this track available + self.file_wu8 = file_wu8 + self.file_szs = file_szs + self.score = score # Track score between 1 and 3 stars + self.warning = warning # Track bug level (1 = minor, 2 = major) + self.note = note # Note about the track + + def get_track_name(self): + prefix = self.prefix + " " if self.prefix else "" + suffix = self.suffix + " " if self.suffix else "" + + name = (prefix + self.name + suffix) + return name + + def get_track_formatted_name(self, highlight_track_from_version: str = None): + """ + :param highlight_track_from_version: if a specific version need to be highlighted. + :return: the name of the track with colored prefix, suffix + """ + hl_prefix = "" + hl_suffix = "" + prefix = "" + suffix = "" + star_text = "" + + if self.score: + if 0 < self.score <= 3: + star_text = "★" * track["score"] + "☆" * (3 - track["score"]) + star_text = trackname_color[star_text] + " " + + if self.since_version == highlight_track_from_version: + hl_prefix, hl_suffix = "\\\\c{blue1}", "\\\\c{off}" + + if self.prefix in trackname_color: + prefix = trackname_color[self.prefix] + " " + if self.suffix in trackname_color: + suffix = "(" + trackname_color[self.suffix] + ")" + + name = (star_text + prefix + hl_prefix + self.name + hl_suffix + suffix) + name = name.replace("_", "") + return name + + def convert_wu8_to_szs(self): + source.wszst.normalize(src_file=self.file_wu8) + + def download_wu8(self): pass + + def check_sha1(self): + if source.wszst.sha1(self.file_wu8) == self.sha1: return 0 + else: return -1 + + def get_ct_file_track(self): pass + + +EMPTY_TRACK = Track("_") diff --git a/source/patch_ct_icon.py b/source/patch_ct_icon.py index ce94e4e..11ff64f 100644 --- a/source/patch_ct_icon.py +++ b/source/patch_ct_icon.py @@ -4,6 +4,30 @@ import math import os +def get_cup_icon(i): + if os.path.exists(f"./file/cup_icon/{id}.png"): + cup_icon = Image.open(f"./file/cup_icon/{id}.png").resize((128, 128)) + + else: + cup_icon = Image.new("RGBA", (128, 128)) + draw = ImageDraw.Draw(cup_icon) + font = ImageFont.truetype("./file/SuperMario256.ttf", 90) + draw.text((4 - 2, 4 - 2), "CT", (0, 0, 0), font=font) + draw.text((4 + 2, 4 - 2), "CT", (0, 0, 0), font=font) + draw.text((4 - 2, 4 + 2), "CT", (0, 0, 0), font=font) + draw.text((4 + 2, 4 + 2), "CT", (0, 0, 0), font=font) + draw.text((4, 4), "CT", (255, 165, 0), font=font) + + font = ImageFont.truetype("./file/SuperMario256.ttf", 60) + draw.text((5 - 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # i-10 because first 8 cup are not + draw.text((5 + 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # counted as new, random cup, + draw.text((5 - 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) # left and right arrow + draw.text((5 + 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) + + draw.text((5, 80), "%03i" % (i - 10), (255, 165, 0), font=font) + return cup_icon + + def patch_ct_icon(self): try: with open("./ct_config.json", encoding="utf8") as f: config = json.load(f) @@ -16,27 +40,7 @@ def patch_ct_icon(self): files.extend(["_"] * ((len(config["tracks_list"]) // 4) + 1)) for i, id in enumerate(files): - if os.path.exists(f"./file/cup_icon/{id}.png"): - cup_icon = Image.open(f"./file/cup_icon/{id}.png").resize((128, 128)) - - else: - cup_icon = Image.new("RGBA", (128, 128)) - draw = ImageDraw.Draw(cup_icon) - font = ImageFont.truetype("./file/SuperMario256.ttf", 90) - draw.text((4 - 2, 4 - 2), "CT", (0, 0, 0), font=font) - draw.text((4 + 2, 4 - 2), "CT", (0, 0, 0), font=font) - draw.text((4 - 2, 4 + 2), "CT", (0, 0, 0), font=font) - draw.text((4 + 2, 4 + 2), "CT", (0, 0, 0), font=font) - draw.text((4, 4), "CT", (255, 165, 0), font=font) - - font = ImageFont.truetype("./file/SuperMario256.ttf", 60) - draw.text((5 - 2, 80 - 2), "%03i" % (i-10), (0, 0, 0), font=font) # i-10 because first 8 cup are not - draw.text((5 + 2, 80 - 2), "%03i" % (i-10), (0, 0, 0), font=font) # counted as new, random cup, - draw.text((5 - 2, 80 + 2), "%03i" % (i-10), (0, 0, 0), font=font) # left and right arrow - draw.text((5 + 2, 80 + 2), "%03i" % (i-10), (0, 0, 0), font=font) - - draw.text((5, 80), "%03i" % (i-10), (255, 165, 0), font=font) - + cup_icon = get_cup_icon(i) ct_icon.paste(cup_icon, (0, i * 128)) ct_icon.save("./file/ct_icons.tpl.png") diff --git a/source/translate.py b/source/translate.py index eb17ed6..4f4f947 100644 --- a/source/translate.py +++ b/source/translate.py @@ -17,5 +17,3 @@ def translate(self, *texts, lang=None): return translated_text return "".join(texts) # if no translation language is found - - diff --git a/source/wszst.py b/source/wszst.py new file mode 100644 index 0000000..3e4a025 --- /dev/null +++ b/source/wszst.py @@ -0,0 +1,30 @@ +from .definition import * +import subprocess + + +def sha1(file): + """ + :param file: track file to check sha1 + :return: track's sha1 + """ + return subprocess.run(["./tools/szs/wszst", "SHA1", file, "--autoadd-path", "./file/auto-add/"], + check=True, creationflags=CREATE_NO_WINDOW, + stdout=subprocess.PIPE).stdout.decode().split(" ")[0] + + +def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = "%N.szs", + output_format: str = "szs", autoadd_path: str = "./file/auto-add/"): + """ + :param src_file: source file + :param dest_dir: destination directory + :param dest_name: destination filename (%N mean same name as src_file) + :param output_format: format of the destination track + :param autoadd_path: path of the auto-add directory + :return: 0 + """ + subprocess.run([ + "./tools/szs/wszst", "NORMALIZE", src_file, "--DEST", + dest_dir+dest_name, "--"+output_format, "--overwrite", "--autoadd-path", + autoadd_path], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE) + return 0 +