diff --git a/file_process.json b/file_process.json index a2fa696a..011ae4b4 100644 --- a/file_process.json +++ b/file_process.json @@ -2,33 +2,76 @@ "bmg": [ { "mode": "overwrite_id", - "language": "fr", + "language": ["en"], "data": { - "0x703e": "\\\\c{{white}}{self.gui.translate('Random: All tracks', lang=bmglang)}\n", - "0x703f": "\\\\c{{white}}{self.gui.translate('Random: Original tracks', lang=bmglang)}\n", - "0x7040": "\\\\c{{white}}{self.gui.translate('Random: Custom Tracks', lang=bmglang)}\n", - "0x7041": "\\\\c{{white}}{self.gui.translate('Random: New tracks', lang=bmglang)}\n" + "0x703e": "\\c{white}Random: All tracks", + "0x703f": "\\c{white}Random: Original tracks", + "0x7040": "\\c{white}Random: Custom Tracks", + "0x7041": "\\c{white}Random: New tracks" + } + }, + { + "mode": "overwrite_id", + "language": ["fr"], + "data": { + "0x703e": "\\c{white}Aléatoire: Toutes les pistes", + "0x703f": "\\c{white}Aléatoire: Pistes Originales", + "0x7040": "\\c{white}Aléatoire: Custom Tracks", + "0x7041": "\\c{white}Aléatoire: Nouvelles pistes" + } + }, + { + "mode": "overwrite_id", + "language": ["ge"], + "data": { + "0x703e": "\\c{white}Zufällig: Alle Tracks", + "0x703f": "\\c{white}Zufällig: Original-Tracks", + "0x7040": "\\c{white}Zufällig: Custom Tracks", + "0x7041": "\\c{white}Zufällig: Neue Tracks" + } + }, + { + "mode": "overwrite_id", + "language": ["it"], + "data": { + "0x703e": "\\c{white}Casuale: Tutte le tracce", + "0x703f": "\\c{white}Casuale: Tracce originali", + "0x7040": "\\c{white}Casuale: Custom Tracks", + "0x7041": "\\c{white}Casuale: Nuovi brani" + } + }, + { + "mode": "overwrite_id", + "language": ["es"], + "data": { + "0x703e": "\\c{white}Aleatorio: Todas las pistas", + "0x703f": "\\c{white}Aleatorio: Pistas originales", + "0x7040": "\\c{white}Aleatorio: Custom Tracks", + "0x7041": "\\c{white}Aleatorio: Pistas nuevas" } }, { "mode": "replace_text", "data": { - "CWF de Nintendo": "{NINTENDO_CWF_REPLACE}", - "Wi-Fi Nintendo": "{NINTENDO_CWF_REPLACE}", - "CWF Nintendo": "{NINTENDO_CWF_REPLACE}", - "Nintendo WFC": "{NINTENDO_CWF_REPLACE}", - "Wi-Fi": "{NINTENDO_CWF_REPLACE}", - "インターネット": "{NINTENDO_CWF_REPLACE}", + "CWF de Nintendo": "{ONLINE_SERVICE}", + "Wi-Fi Nintendo": "{ONLINE_SERVICE}", + "CWF Nintendo": "{ONLINE_SERVICE}", + "Nintendo WFC": "{ONLINE_SERVICE}", + "Wi-Fi": "{ONLINE_SERVICE}", + "インターネット": "{ONLINE_SERVICE}", - "Menu principal": "{MAINMENU_REPLACE}", - "Menú principal": "{MAINMENU_REPLACE}", - "Main Menu": "{MAINMENU_REPLACE}", - "トップメニュー": "{MAINMENU_REPLACE}", + "Menu principal": "{MOD_NICKNAME} v{MOD_VERSION}{MOD_CUSTOMIZED}", + "Menú principal": "{MOD_NICKNAME} v{MOD_VERSION}{MOD_CUSTOMIZED}", + "Main Menu": "{MOD_NICKNAME} v{MOD_VERSION}{MOD_CUSTOMIZED}", + "トップメニュー": "{MOD_NICKNAME} v{MOD_VERSION}{MOD_CUSTOMIZED}", - "Mario Kart Wii": "{MAINMENU_REPLACE}" + "Mario Kart Wii": "{MOD_NICKNAME} v{MOD_VERSION}{MOD_CUSTOMIZED}" } } ], + + + "img": { "tt_hatena_64x64.tpl.png": "TPL.RGB5A3", "tt_obi_bottom_curve_000.tpl.png": "TPL.RGB5A3", diff --git a/requirements.txt b/requirements.txt index 92ea7d3c..59988b43 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ requests pillow -cx_Freeze -fstring \ No newline at end of file +cx_Freeze \ No newline at end of file diff --git a/source/Game.py b/source/Game.py index 69f8fc0c..4da984f7 100644 --- a/source/Game.py +++ b/source/Game.py @@ -114,7 +114,12 @@ def convert_to(self, format: str = "FST") -> None: self.path = path_game_format self.gui.progress(statut=self.gui.translate("Changing game's ID"), add=1) - wit.edit(file=self.path, region_ID=self.region_ID, name=f"Mario Kart Wii Faraphel {self.ctconfig.version}") + wit.edit( + file=self.path, + region_ID=self.region_ID, + game_variant=self.ctconfig.game_variant, + name=f"Mario Kart Wii Faraphel {self.ctconfig.version}" + ) def extract(self) -> None: """ @@ -335,27 +340,12 @@ def patch_bmg(self, gamefile: str) -> None: :param gamefile: an .szs file where file will be patched """ - NINTENDO_CWF_REPLACE = "Wiimmfi" - _customized = " (custom)" - MAINMENU_REPLACE = ( - f"MKWFaraphel {self.ctconfig.version}" + - ("" if self.gui.is_using_official_config() else _customized) - ) - - menu_replacement = { - "CWF de Nintendo": NINTENDO_CWF_REPLACE, - "Wi-Fi Nintendo": NINTENDO_CWF_REPLACE, - "CWF Nintendo": NINTENDO_CWF_REPLACE, - "Nintendo WFC": NINTENDO_CWF_REPLACE, - "Wi-Fi": NINTENDO_CWF_REPLACE, - "インターネット": NINTENDO_CWF_REPLACE, - - "Menu principal": MAINMENU_REPLACE, - "Menú principal": MAINMENU_REPLACE, - "Main Menu": MAINMENU_REPLACE, - "トップメニュー": MAINMENU_REPLACE, - - "Mario Kart Wii": MAINMENU_REPLACE, + bmg_replacement = { + "MOD_NAME": self.ctconfig.name, + "MOD_NICKNAME": self.ctconfig.nickname, + "MOD_VERSION": self.ctconfig.version, + "MOD_CUSTOMIZED": "" if self.gui.is_using_official_config() else " (custom)", + "ONLINE_SERVICE": "Wiimmfi", } bmglang = gamefile[-len("E.txt"):-len(".txt")] # Langue du fichier @@ -364,40 +354,44 @@ def patch_bmg(self, gamefile: str) -> None: szs.extract(file=gamefile) bmgmenu = bmg.cat(path=gamefile, subfile=".d/message/Menu.bmg") # Menu.bmg - bmgtracks = bmg.cat(path=gamefile, subfile=".d/message/Common.bmg") # Common.bmg trackheader = "#--- standard track names" trackend = "2328" + bmgtracks = bmg.cat(path=gamefile, subfile=".d/message/Common.bmg") # Common.bmg bmgtracks = bmgtracks[bmgtracks.find(trackheader) + len(trackheader):bmgtracks.find(trackend)] - with open("./file/ExtraCommon.txt", "w", encoding="utf8") as f: - f.write("#BMG\n\n" - f" 703e\t= \\\\c{{white}}{self.gui.translate('Random: All tracks', lang=bmglang)}\n" - f" 703f\t= \\\\c{{white}}{self.gui.translate('Random: Original tracks', lang=bmglang)}\n" - f" 7040\t= \\\\c{{white}}{self.gui.translate('Random: Custom Tracks', lang=bmglang)}\n" - f" 7041\t= \\\\c{{white}}{self.gui.translate('Random: New tracks', lang=bmglang)}\n") - - for bmgtrack in bmgtracks.split("\n"): - if "=" in bmgtrack: - - prefix = "" - track_name = bmgtrack[bmgtrack.find("= ") + 2:] - - if "T" in bmgtrack[:bmgtrack.find("=")]: - start_track_id: int = bmgtrack.find("T") # index where the bmg track definition start - track_id = bmgtrack[start_track_id:start_track_id + 3] - if track_id[1] in "1234": # if the track is a original track from the wii - prefix = trackname_color["Wii"] + " " - elif track_id[1] in "5678": # if the track is a retro track from the original game - for color_prefix, rep_color_prefix in trackname_color.items(): # color retro track prefix - track_name = track_name.replace(color_prefix, rep_color_prefix) - track_id = hex(bmgID_track_move[track_id])[2:] - else: # Arena - start_track_id = bmgtrack.find("U") + 1 # index where the bmg arena definition start - track_id = bmgtrack[start_track_id:start_track_id + 2] - track_id = hex((int(track_id[0]) - 1) * 5 + (int(track_id[1]) - 1) + 0x7020)[2:] - - f.write(f" {track_id}\t= {prefix}{track_name}\n") + def create_extra_common(extra_common_path: str = "./file/ExtraCommon.txt") -> None: + """ + this function create an "extra common" file : it contain modification about the original tracks name + (the color modification) and allow the modification to be applied by overwritting the normal common + file by this one. + :param extra_common_path: destination path to the extra common file + """ + with open(extra_common_path, "w", encoding="utf8") as f: + f.write("#BMG\n") + + for bmgtrack in bmgtracks.split("\n"): + if "=" in bmgtrack: + + prefix = "" + track_name = bmgtrack[bmgtrack.find("= ") + 2:] + + if "T" in bmgtrack[:bmgtrack.find("=")]: + start_track_id: int = bmgtrack.find("T") # index where the bmg track definition start + track_id = bmgtrack[start_track_id:start_track_id + 3] + if track_id[1] in "1234": # if the track is a original track from the wii + prefix = trackname_color["Wii"] + " " + elif track_id[1] in "5678": # if the track is a retro track from the original game + for color_prefix, rep_color_prefix in trackname_color.items(): # color retro track prefix + track_name = track_name.replace(color_prefix, rep_color_prefix) + track_id = hex(bmgID_track_move[track_id])[2:] + else: # Arena + start_track_id = bmgtrack.find("U") + 1 # index where the bmg arena definition start + track_id = bmgtrack[start_track_id:start_track_id + 2] + track_id = hex((int(track_id[0]) - 1) * 5 + (int(track_id[1]) - 1) + 0x7020)[2:] + + f.write(f" {track_id}\t= {prefix}{track_name}\n") + create_extra_common() bmgcommon = ctc.patch_bmg(ctfile="./file/CTFILE.txt", bmgs=[gamefile + ".d/message/Common.bmg", "./file/ExtraCommon.txt"]) @@ -407,17 +401,61 @@ def patch_bmg(self, gamefile: str) -> None: shutil.rmtree(gamefile + ".d") os.remove("./file/ExtraCommon.txt") - def finalise(file, bmgtext, replacement_list=None): - if replacement_list: - for text, colored_text in replacement_list.items(): bmgtext = bmgtext.replace(text, colored_text) - with open(file, "w", encoding="utf-8") as f: - f.write(bmgtext) + def process_bmg_replacement(bmg_content: str, bmg_language: str) -> str: + """ + This function apply the file_process to the bmg file. This allow text modification useful to + change menu text (Wiimmfi for example) and the Wiimm's cup. + :param bmg_content: content of the bmg to process + :param bmg_language: language of the bmg file + :return: the replaced bmg file + """ + with open("./file_process.json", encoding="utf8") as fp_file: + file_process = json.load(fp_file) + + for bmg_process in file_process["bmg"]: + if "only_file" in bmg_process: + if not os.path.basename(file) in bmg_process["only_file"]: + continue + + if bmg_language and "language" in bmg_process: + if gamelang_to_lang[bmg_language] in bmg_process["language"]: + continue + + for data, data_replacement in bmg_process["data"].items(): + for key, replacement in bmg_replacement.items(): + data_replacement = data_replacement.replace("{"+key+"}", replacement) + + if bmg_process["mode"] == "overwrite_id": + start_line = f"\n\t{str_to_int(data):x} = " + start_pos = bmg_content.find(start_line) + if start_pos != -1: + end_pos = bmg_content[start_pos:].find("\n") + bmg_content = ( + bmg_content[:start_pos] + + start_line + data_replacement + + bmg_content[end_pos:] + ) + else: + bmg_content = f"{bmg_content}\n{start_line}{data_replacement}\n" + + elif bmg_process["mode"] == "replace_text": + bmg_content = bmg_content.replace(data, data_replacement) + + return bmg_content + + def save_bmg(file: str, bmg_content: str) -> None: + """ + Save and encode the bmg + :param file: name of the bmg-text to save + :param bmg_content: content to save in the bmg-text + """ + with open(file, "w", encoding="utf-8") as f: f.write(bmg_content) bmg.encode(file) os.remove(file) - finalise(f"./file/Menu_{bmglang}.txt", bmgmenu, menu_replacement) - finalise(f"./file/Common_{bmglang}.txt", bmgcommon) - finalise(f"./file/Common_R{bmglang}.txt", rbmgcommon) + save_bmg(f"./file/Menu_{bmglang}.txt", process_bmg_replacement(bmgmenu, bmglang)) + save_bmg(f"./file/Common_{bmglang}.txt", process_bmg_replacement(bmgcommon, bmglang)) + save_bmg(f"./file/Common_R{bmglang}.txt", process_bmg_replacement(rbmgcommon, bmglang)) def patch_file(self): """ @@ -425,9 +463,9 @@ def patch_file(self): """ try: if not (os.path.exists("./file/Track-WU8/")): os.makedirs("./file/Track-WU8/") - with open("./file_process.json") as f: - fc = json.load(f) - max_step = len(fc["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS") + with open("./file_process.json", encoding="utf8") as fp_file: + file_process = json.load(fp_file) + max_step = len(file_process["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS") self.gui.progress(show=True, indeter=False, statut=self.gui.translate("Converting files"), max=max_step, step=0) @@ -443,7 +481,7 @@ def patch_file(self): self.gui.progress(statut=self.gui.translate("Creating descriptive images"), add=1) self.patch_img_desc() - self.patch_image(fc) + self.patch_image(file_process["img"]) for file in glob.glob(self.path + "/files/Scene/UI/MenuSingle_?.szs"): self.patch_bmg(file) # MenuSingle could be any other file, Common and Menu are all the same in all other files. self.patch_autoadd() @@ -454,15 +492,15 @@ def patch_file(self): finally: self.gui.progress(show=False) - def patch_image(self, fc: dict) -> None: + def patch_image(self, fp_img: dict) -> None: """ Convert .png image into the format wrote in convert_file - :param fc: file convert, a dictionnary indicating which format a file need to be converted + :param fp_img: file convert, a dictionnary indicating which format a file need to be converted """ - for i, file in enumerate(fc["img"]): - self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fc['img'])}) {file}", + for i, file in enumerate(fp_img): + self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fp_img)}) {file}", add=1) - img.encode(file="./file/" + file, format=fc["img"][file]) + img.encode(file="./file/" + file, format=fp_img[file]) def patch_img_desc(self, img_desc_path: str = "./file/img_desc/", dest_dir: str = "./file/") -> None: """ diff --git a/source/Gui.py b/source/Gui.py index 886e4533..ea248529 100644 --- a/source/Gui.py +++ b/source/Gui.py @@ -326,18 +326,14 @@ def state_button(self, enable: bool = True) -> None: else: widget.config(state=DISABLED) - def translate(self, *texts, lang: str = None) -> str: + def translate(self, *texts, gamelang: str = None) -> str: """ translate text into an another language in translation.json file :param texts: all text to convert - :param lang: force a destination language to convert track + :param gamelang: force a destination language to convert track :return: translated text """ - if lang is None: lang = self.stringvar_language.get() - elif lang == "F": lang = "fr" - elif lang == "G": lang = "ge" - elif lang == "I": lang = "it" - elif lang == "S": lang = "sp" + lang = gamelang_to_lang.get(gamelang, self.stringvar_language.get()) if lang in translation_dict: _lang_trad = translation_dict[lang] diff --git a/source/Track.py b/source/Track.py index ab75beb3..19329dbd 100644 --- a/source/Track.py +++ b/source/Track.py @@ -26,7 +26,7 @@ class Track: def __init__(self, name: str = "_", 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 = "", track_wu8_dir: str = "./file/Track-WU8/", - track_szs_dir: str = "./file/Track/", *args, **kwargs): + track_szs_dir: str = "./file/Track/", track_version: str = None, tags: list = [], *args, **kwargs): """ Track class :param name: track name @@ -45,6 +45,9 @@ def __init__(self, name: str = "_", prefix: str = None, suffix: str = None, :param note: note about the track :param track_wu8_dir: where is stored the track wu8 :param track_szs_dir: where is stored the track szs + :param track_version: version of the track + :param tags: a list of tags that correspond to the track + :param args: / :param kwargs: / """ @@ -65,6 +68,8 @@ def __init__(self, name: str = "_", prefix: str = None, suffix: str = None, self.track_szs_dir = track_szs_dir self.file_wu8 = f"{track_wu8_dir}/{self.get_track_name()}.wu8" self.file_szs = f"{track_szs_dir}/{self.get_track_name()}.szs" + self.track_version = track_version + self.tags = tags def __repr__(self) -> str: """ @@ -192,3 +197,6 @@ def load_from_json(self, track_json: dict) -> None: self.file_wu8 = f"{self.track_wu8_dir}/{self.get_track_name()}.wu8" self.file_szs = f"{self.track_szs_dir}/{self.get_track_name()}.szs" + + def create_from_track_file(self, track_file: str) -> None: + pass diff --git a/source/definition.py b/source/definition.py index d9a3263a..fd5d7ae0 100644 --- a/source/definition.py +++ b/source/definition.py @@ -92,6 +92,20 @@ "E": "USA" } +gamelang_to_lang = { + "E": "en", # english (UK) + "U": "en", # english (America) + "F": "fr", # french (France) + "Q": "fr", # french (Quebec) + "G": "ge", # german + "I": "it", # italian + "S": "es", # spanish (Spain) + "M": "es", # spanish (Mexico) + + "J": "en", # japan - no translation + "K": "en", # korean - no translation +} + warning_color = { 1: "\\\\c{YOR4}", 2: "\\\\c{YOR6}", @@ -100,6 +114,7 @@ get_version_from_string = lambda v: list(map(int, v.split('.'))) + def restart(): """ restart the application @@ -114,6 +129,7 @@ def in_thread(func): :param func: function to thread :return: threaded function """ + def wrapped_func(*args, **kwargs) -> Thread: """ function that will be returned instead of the function, will call it in a thread @@ -145,3 +161,7 @@ def get_next_available_dir(parent_dir: str, dir_name: str) -> str: i += 1 +def str_to_int(string: str) -> int: + base: int = 10 + if string.startswith("0x"): base = 16 + return int(string, base=base) diff --git a/translation.json b/translation.json index 48eb8527..64f955f5 100644 --- a/translation.json +++ b/translation.json @@ -46,10 +46,6 @@ "The mod has been installed !": "L'installation est terminé !", "An error occured": "Une erreur est survenue", "Patching text": "Patch des textes", - "Random: All tracks": "Aléatoire: Toutes les pistes", - "Random: Original tracks": "Aléatoire: Pistes Originales", - "Random: Custom Tracks": "Aléatoire: Custom Tracks", - "Random: New tracks": "Aléatoire: Pistes Nouvelles", "Converting files": "Conversion des fichiers", "Configurating LE-CODE": "Configuration de LE-CODE", "Creating ct_icon.png": "Création de ct_icon.png", @@ -71,23 +67,5 @@ "None": "Aucune", "MB": "Mo", "GB": "Go" - }, - "ge": { - "Random: All tracks": "Zufällig: Alle Tracks", - "Random: Original tracks": "Zufällig: Original-Tracks", - "Random: Custom Tracks": "Zufällig: Custom Tracks", - "Random: New tracks": "Zufällig: Neue Tracks" - }, - "it": { - "Random: All tracks": "Casuale: Tutte le tracce", - "Random: Original tracks": "Casuale: Tracce originali", - "Random: Custom Tracks": "Casuale: Custom Tracks", - "Random: New tracks": "Casuale: Nuovi brani" - }, - "sp": { - "Random: All tracks": "Aleatorio: Todas las pistas", - "Random: Original tracks": "Aleatorio: Pistas originales", - "Random: Custom Tracks": "Aleatorio: Custom Tracks", - "Random: New tracks": "Aleatorio: Pistas nuevas" } } \ No newline at end of file