edited source to use CT_Config, Game, Cup and Track

This commit is contained in:
raphael60650 2021-07-17 19:30:51 +02:00
parent c041f55cb9
commit 57efdf2da3
20 changed files with 169 additions and 375 deletions

View file

@ -20,18 +20,18 @@ class ClassApp():
from source.Progress import Progress
from source.check_update import check_update
from source.StateButton import StateButton
from source.create_lecode_config import create_lecode_config
from source.patch_file import patch_file
from source.patch_bmg import patch_bmg
from source.install_mod import install_mod
from source.restart import restart
from source.patch_img_desc import patch_img_desc
from source.patch_ct_icon import patch_ct_icon
from source.log_error import log_error
from source.get_github_file import get_github_file, check_track_sha1
from source.patch_track import load_ct_config, patch_track, patch_autoadd, get_trackctname, get_trackname
from source.get_github_file import get_github_file
from source.patch_track import patch_track, patch_autoadd
from source.patch_image import patch_image
from source.option import load_option, change_option
from source.CT_Config import CT_Config
from source.Game import Game, InvalidGamePath, InvalidFormat
App = ClassApp()

View file

@ -1,30 +1,37 @@
from .Cup import *
import math
from PIL import Image, ImageFont, ImageDraw
import json
import os
def get_cup_icon(i):
if os.path.exists(f"./file/cup_icon/{i}.png"):
cup_icon = Image.open(f"./file/cup_icon/{i}.png").resize((128, 128))
def get_cup_icon(cup_id, font_path: str = "./file/SuperMario256.ttf", cup_icon_dir: str = "./file/cup_icon"):
"""
:param cup_icon_dir: directory to cup icon
:param font_path: path to the font used to generate icon
:param cup_id: id of the cup
:return: cup icon
"""
if os.path.exists(f"{cup_icon_dir}/{cup_id}.png"):
cup_icon = Image.open(f"{cup_icon_dir}/{cup_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)
font = ImageFont.truetype(font_path, 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, (0, 0, 0), font=font)
draw.text((5 + 2, 80 - 2), "%03i" % i, (0, 0, 0), font=font)
draw.text((5 - 2, 80 + 2), "%03i" % i, (0, 0, 0), font=font)
draw.text((5 + 2, 80 + 2), "%03i" % i, (0, 0, 0), font=font)
font = ImageFont.truetype(font_path, 60)
draw.text((5 - 2, 80 - 2), "%03i" % cup_id, (0, 0, 0), font=font)
draw.text((5 + 2, 80 - 2), "%03i" % cup_id, (0, 0, 0), font=font)
draw.text((5 - 2, 80 + 2), "%03i" % cup_id, (0, 0, 0), font=font)
draw.text((5 + 2, 80 + 2), "%03i" % cup_id, (0, 0, 0), font=font)
draw.text((5, 80), "%03i" % i, (255, 165, 0), font=font)
draw.text((5, 80), "%03i" % cup_id, (255, 165, 0), font=font)
return cup_icon

View file

@ -1,6 +1,4 @@
from .Track import *
from PIL import Image
from .patch_ct_icon import get_cup_icon
class Cup:
@ -8,8 +6,7 @@ class Cup:
track1: Track = None,
track2: Track = None,
track3: Track = None,
track4: Track = None,
icon: Image = None, locked: bool = False,
track4: Track = None, locked: bool = False,
*args, **kwargs):
self.name = name
@ -19,7 +16,6 @@ class Cup:
track3 if track3 else Track(),
track4 if track4 else Track()
]
self.icon = icon
self.locked = locked
def load_from_json(self, cup: dict):
@ -38,10 +34,3 @@ class Cup:
for track in self.tracks:
ctfile_cup += track.get_ctfile_track(race)
return ctfile_cup
def get_icon(self, id: int):
"""
:param id: cup number
:return: icon of the cup
"""
return self.icon if self.icon else get_cup_icon(id)

View file

@ -3,33 +3,52 @@ from .definition import *
import glob
import os
region_id_to_name = {
"J": "JAP",
"P": "PAL",
"K": "KO",
"E": "USA"
}
class InvalidGamePath(Exception):
def __init__(self):
super().__init__("This path is not valid !")
class InvalidFormat(Exception):
def __init__(self):
super().__init__("This game format is not supported !")
class Game:
def __init__(self, path: str, region: str = "PAL", game_ID: str = "RMCP01"):
self.extension = get_extension(path)
def __init__(self, path: str, region_ID: str = "P", game_ID: str = "RMCP01"):
if not os.path.exists(path): raise InvalidGamePath()
self.extension = get_extension(path).upper()
self.path = path
self.region_ID = region_ID[region]
self.region = region
self.region = region_id_to_name[region_ID]
self.region_ID = region_ID
self.game_ID = game_ID
def extract_game(self):
if self.extension.upper() == "DOL":
if self.extension == "DOL":
self.path = os.path.realpath(self.path + "/../../") # main.dol is in PATH/sys/, so go back 2 dir upper
elif self.extension.upper() in ["ISO", "WBFS", "CSIO"]:
elif self.extension in ["ISO", "WBFS", "CSIO"]:
# Fiding a directory name that doesn't already exist
directory_name, i = "MKWiiFaraphel", 1
while True:
self.path = os.path.realpath(self.path + f"/../{directory_name}")
if not (os.path.exists(self.path)): break
path_dir = os.path.realpath(self.path + f"/../{directory_name}")
if not (os.path.exists(path_dir)): break
directory_name, i = f"MKWiiFaraphel ({i})", i + 1
wszst.extract(self.path, self.path)
wszst.extract(self.path, path_dir)
self.path = path_dir
if os.path.exists(self.path + "/DATA"): self.path += "/DATA"
self.extension = "DOL"
else:
raise Exception("This format is not supported !")
raise InvalidFormat()
if glob.glob(self.path + "/files/rel/lecode-???.bin"): # if a LECODE file is already here
raise Warning("ROM Already patched") # warning already patched
@ -39,7 +58,7 @@ class Game:
self.game_ID = setup[:setup.find("\n")]
self.region_ID = self.game_ID[3]
self.region = region_ID[self.region_ID] if self.region_ID in region_ID else self.region
self.region = region_id_to_name[self.region_ID] if self.region_ID in region_id_to_name else self.region
def install_mod(self):
pass

View file

@ -1,16 +1,15 @@
def Progress(self, show=None, indeter=None, step=None, statut=None, max=None, add=None):
if indeter == True:
if indeter is True:
self.progressbar.config(mode="indeterminate")
self.progressbar.start(50)
elif indeter == False:
elif indeter is False:
self.progressbar.config(mode="determinate")
self.progressbar.stop()
if show == True:
if show is True:
self.StateButton(enable=False)
self.progressbar.grid(row=100, column=1, sticky="NEWS")
self.progresslabel.grid(row=101, column=1, sticky="NEWS")
elif show == False:
elif show is False:
self.StateButton(enable=True)
self.progressbar.grid_forget()
self.progresslabel.grid_forget()

View file

@ -19,11 +19,11 @@ class Track:
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
self.file_wu8 = file_wu8
self.file_szs = file_szs
self.file_wu8 = f"./file/Track-WU8/{self.get_track_name()}.wu8"
self.file_szs = f"./file/Track/{self.get_track_name()}.szs"
def __repr__(self):
return f"{self.get_track_name()} sha1={self.sha1}"
return f"{self.get_track_name()} sha1={self.sha1} score={self.score}"
def get_track_name(self):
prefix = self.prefix + " " if self.prefix else ""
@ -61,11 +61,11 @@ class Track:
suffix = "(" + trackname_color[self.suffix] + ")"
name = (star_text + prefix + hl_prefix + self.name + hl_suffix + suffix)
name = name.replace("_", "")
name = name.replace("_", " ")
return name
def convert_wu8_to_szs(self):
source.wszst.normalize(src_file=self.file_wu8)
return source.wszst.normalize(src_file=self.file_wu8, use_popen=True)
def download_wu8(self): pass
@ -96,3 +96,5 @@ class Track:
)
return ctfile_text
# TODO: code download_wu8

View file

@ -8,14 +8,16 @@ import os
from .definition import *
from .check_update import check_update
from .translate import translate
from .CT_Config import *
from .Game import *
def __init__(self):
try:
self.root = Tk()
self.load_option()
self.load_ct_config()
self.ctconfig = CT_Config()
self.ctconfig.load_ctconfig_file("./ct_config.json")
self.stringvar_language = StringVar(value=self.option["language"])
self.stringvar_game_format = StringVar(value=self.option["format"])
@ -61,7 +63,7 @@ def __init__(self):
self.menu_marktrackversion = Menu(self.menu_trackselection, tearoff=0)
self.menu_trackselection.add_cascade(label=self.translate("Mark all tracks from version"), menu=self.menu_marktrackversion)
self.menu_marktrackversion.add_radiobutton(label=self.translate("None"), variable=self.stringvar_mark_track_from_version, value="None")
for version in self.ALL_VERSION:
for version in self.ctconfig.all_version:
self.menu_marktrackversion.add_radiobutton(label=f"v{version}", variable=self.stringvar_mark_track_from_version, value=version)
self.menu_advanced = Menu(self.menu_bar, tearoff=0)
@ -103,62 +105,18 @@ def __init__(self):
def use_path():
def func():
self.frame_action.grid_forget()
try:
self.frame_action.grid_forget()
path = entry_game_path.get()
if not (os.path.exists(path)):
messagebox.showerror(self.translate("Error"), self.translate("The file path in invalid"))
return
extension = get_extension(path)
if extension.upper() == "DOL":
if messagebox.askyesno(self.translate("Warning"),
self.translate("This directory will be overwritten if you install the "
"mod !\n Are you sure you want to use it ?")):
self.path_mkwf = os.path.realpath(path + "/../../")
else: return
elif extension.upper() in ["ISO", "WBFS", "CSIO"]:
# Fiding a directory name that dosen't already exist
directory_name, i = "MKWiiFaraphel", 1
while True:
self.path_mkwf = os.path.realpath(path + f"/../{directory_name}")
if not(os.path.exists(self.path_mkwf)): break
directory_name, i = f"MKWiiFaraphel ({i})", i + 1
self.Progress(show=True, indeter=True, statut=self.translate("Extracting the game..."))
subprocess.call(["./tools/wit/wit", "EXTRACT", get_nodir(path), "--DEST", directory_name]
, creationflags=CREATE_NO_WINDOW, cwd=get_dir(path))
if os.path.exists(self.path_mkwf + "/DATA"): self.path_mkwf += "/DATA"
self.Progress(show=False)
else:
messagebox.showerror(self.translate("Error"), self.translate("This file type is not supported"))
self.Progress(show=False)
return
if glob.glob(self.path_mkwf + "/files/rel/lecode-???.bin"): # if a LECODE file is already here
messagebox.showwarning(self.translate("Warning"),
self.translate("This game is already modded, it is not recommended to "
"use it to install the mod"))
try:
with open(self.path_mkwf + "/setup.txt") as f: setup = f.read()
setup = setup[setup.find("!part-id = ")+len("!part-id = "):]
self.original_game_ID = setup[:setup.find("\n")]
except:
messagebox.showwarning(self.translate("Warning"),
self.transate("Can't find game region.\nPAL region will be used."))
self.original_game_ID = "RMCP01"
try:
self.original_region_ID = self.original_game_ID[3]
self.original_region = region_ID[self.original_region_ID]
except: self.original_region = "PAL"
self.game = Game(path = entry_game_path.get())
self.Progress(show=True, indeter=True, statut=self.translate("Extracting the game..."))
self.game.extract_game()
self.frame_action.grid(row=3, column=1, sticky="NEWS")
except: self.log_error()
except InvalidGamePath:
messagebox.showerror(self.translate("Error"), self.translate("The file path in invalid"))
except InvalidFormat:
messagebox.showerror(self.translate("Error"), self.translate("This game's format is invalid"))
except:
self.log_error()
finally:
self.Progress(show=False)

View file

@ -2,7 +2,6 @@ from tkinter import messagebox
import requests
import zipfile
import json
import sys
import os
from .definition import *
@ -38,12 +37,10 @@ def check_update(self):
os.remove("./download.zip")
print(self.translate("starting application..."))
os.startfile(os.path.realpath("./Updater/Updater.exe"))
sys.exit()
except requests.ConnectionError:
messagebox.showwarning(self.translate("Warning"),
self.translate("Can't connect to internet. Download will be disabled."))
self.option["disable_download"] = True
except SystemExit: pass
except: self.log_error()

View file

@ -1,80 +0,0 @@
import json
from .definition import *
def create_lecode_config(self):
try:
def get_star_text(track):
if "score" in track:
if 0 < track["score"] <= 3:
star_text = "" * track["score"] + "" * (3 - track["score"])
return trackname_color[star_text] + " "
return ""
def get_ctfile_text(track, race=False):
if race:
return (f' T {track["music"]}; '
f'{track["special"]}; '
f'{"0x01" if track["new"] else "0x00"}; '
f'"-"; '
f'"{get_star_text(track)}{self.get_trackctname(track=track, color=True)}\\n{track["author"]}"; '
f'"-"\n')
else:
return (f' T {track["music"]}; '
f'{track["special"]}; '
f'{"0x01" if track["new"] else "0x00"}; '
f'"{self.get_trackctname(track=track)}"; '
f'"{get_star_text(track)}{self.get_trackctname(track=track, color=True)}"; '
f'"-"\n')
with open("./ct_config.json", encoding="utf-8") as f:
ctconfig = json.load(f)
with open("./file/CTFILE.txt", "w", encoding="utf-8") as ctfile, \
open("./file/RCTFILE.txt", "w", encoding="utf-8") as rctfile:
header = ("#CT-CODE\n"
"[RACING-TRACK-LIST]\n"
"%LE-FLAGS=1\n"
"%WIIMM-CUP=1\n"
"N N$SWAP | N$F_WII\n\n")
ctfile.write(header)
rctfile.write(header)
for cup in ctconfig["cup"]: # defined cup section
_cup_config = ctconfig["cup"][cup]
if int(cup) >= 9: # Track that are not original and not random selection
cup = f'\nC "{_cup_config["name"]}"\n'
ctfile.write(cup)
rctfile.write(cup)
for course in _cup_config["courses"]:
_course_config = _cup_config["courses"][course]
ctfile.write(get_ctfile_text(_course_config, race=False))
rctfile.write(get_ctfile_text(_course_config, race=True))
tracks_list = ctconfig["tracks_list"]
if not self.boolvar_use_1star_track.get(): # if 1 star track are disabled, remove them
tracks_list = list(filter(lambda track: track.get("score") != 1, tracks_list))
if not self.boolvar_use_2star_track.get(): # if 2 stars track are disabled, remove them
tracks_list = list(filter(lambda track: track.get("score") != 2, tracks_list))
if not self.boolvar_use_3star_track.get(): # if 3 stars track are disabled, remove them
tracks_list = list(filter(lambda track: track.get("score") != 3, tracks_list))
# using dict.get allow track that with no "score" attribute to not raise an exception by returning None
for i, _course_config in enumerate(tracks_list): # undefined cup section
if i % 4 == 0:
cup = f'\nC "TL{i//4}"\n'
ctfile.write(cup)
rctfile.write(cup)
ctfile.write(get_ctfile_text(_course_config, race=False))
rctfile.write(get_ctfile_text(_course_config, race=True))
for _ in range(1, 4-(i%4)): # Complete cup if track are missing
ctfile.write(EMPTY_TRACK)
rctfile.write(EMPTY_TRACK)
except:
self.log_error()

View file

@ -1,5 +1,3 @@
import json
CREATE_NO_WINDOW = 0x08000000
GITHUB_REPOSITORY = "Faraphel/MKWF-Install"
GITHUB_CONTENT_ROOT = f"https://raw.githubusercontent.com/{GITHUB_REPOSITORY}/master/"
@ -9,31 +7,19 @@ get_filename = lambda file: ".".join(file.split(".")[:-1])
get_nodir = lambda file: file.replace("\\", "/").split("/")[-1]
get_dir = lambda file: "/".join(file.replace("\\", "/").split("/")[:-1])
get_extension = lambda file: file.split(".")[-1]
get_track_wu8 = lambda track: f"./file/Track-WU8/{track}.wu8"
get_track_szs = lambda track: f"./file/Track/{track}.szs"
region_ID = {
"J": "JAP",
"P": "PAL",
"K": "KO",
"E": "USA"
}
EMPTY_TRACK = ' T T44; T44; 0x00; "_"; ""; "-"\n'
with open("./translation.json", encoding="utf-8") as f:
translation_dict = json.load(f)
bmgID_track_move = {
"T11": 0x7008, "T12": 0x7001, "T13": 0x7002, "T14": 0x7004,
"T21": 0x7000, "T22": 0x7005, "T23": 0x7006, "T24": 0x7007,
"T31": 0x7009, "T32": 0x700f, "T33": 0x700b, "T34": 0x7003,
"T41": 0x700e, "T42": 0x700a, "T43": 0x700c, "T44": 0x700d,
"T11": 0x7008, "T12": 0x7001, "T13": 0x7002, "T14": 0x7004,
"T21": 0x7000, "T22": 0x7005, "T23": 0x7006, "T24": 0x7007,
"T31": 0x7009, "T32": 0x700f, "T33": 0x700b, "T34": 0x7003,
"T41": 0x700e, "T42": 0x700a, "T43": 0x700c, "T44": 0x700d,
"T51": 0x7010, "T52": 0x7014, "T53": 0x7019, "T54": 0x701a,
"T61": 0x701b, "T62": 0x701f, "T63": 0x7017, "T64": 0x7012,
"T71": 0x7015, "T72": 0x701e, "T73": 0x701d, "T74": 0x7011,
"T81": 0x7018, "T82": 0x7016, "T83": 0x7013, "T84": 0x701c,
"T51": 0x7010, "T52": 0x7014, "T53": 0x7019, "T54": 0x701a,
"T61": 0x701b, "T62": 0x701f, "T63": 0x7017, "T64": 0x7012,
"T71": 0x7015, "T72": 0x701e, "T73": 0x701d, "T74": 0x7011,
"T81": 0x7018, "T82": 0x7016, "T83": 0x7013, "T84": 0x701c,
}
trackname_color = {
"MSRDS": "\\\\c{green}MSRDS\\\\c{off}",

View file

@ -1,5 +1,4 @@
import requests
import subprocess
import os
from .definition import *
@ -29,10 +28,4 @@ def get_github_file(self, file):
self.log_error()
return -1
def check_track_sha1(self, file, excepted_sha1):
sha1 = 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]
if excepted_sha1 == sha1: return 0
else: return -1
# TODO: if version > github version, do not search in master branch but dev branch

View file

@ -28,7 +28,7 @@ def install_mod(self):
max_step += 1
for fp in fs:
for f in glob.glob(self.path_mkwf + "/files/" + fp, recursive=True):
for f in glob.glob(self.game.path + "/files/" + fp, recursive=True):
if type(fs[fp]) == str:
count_rf(path=f)
elif type(fs[fp]) == dict:
@ -66,7 +66,7 @@ def install_mod(self):
filecopy(f"./file/{file}", path)
for fp in fs:
for f in glob.glob(self.path_mkwf + "/files/" + fp, recursive=True):
for f in glob.glob(self.game.path + "/files/" + fp, recursive=True):
if type(fs[fp]) == str:
replace_file(path=f, file=fs[fp])
elif type(fs[fp]) == dict:
@ -84,43 +84,44 @@ def install_mod(self):
if os.path.exists(file + ".d"): shutil.rmtree(file + ".d")
self.Progress(statut=self.translate("Patch main.dol"), add=1)
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.path_mkwf) + "/sys/main.dol", "--clean-dol",
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf),
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.game.path) + "/sys/main.dol", "--clean-dol",
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
check=True, stdout=subprocess.PIPE)
self.Progress(statut=self.translate("Patch lecode.bin"), add=1)
shutil.copytree("./file/Track/", self.path_mkwf+"/files/Race/Course/", dirs_exist_ok=True)
if not(os.path.exists(self.path_mkwf+"/tmp/")): os.makedirs(self.path_mkwf+"/tmp/")
filecopy("./file/CTFILE.txt", self.path_mkwf+"/tmp/CTFILE.txt")
filecopy("./file/lpar-default.txt", self.path_mkwf + "/tmp/lpar-default.txt")
filecopy(f"./file/lecode-{self.original_region}.bin", self.path_mkwf + f"/tmp/lecode-{self.original_region}.bin")
shutil.copytree("./file/Track/", self.game.path+"/files/Race/Course/", dirs_exist_ok=True)
if not(os.path.exists(self.game.path+"/tmp/")): os.makedirs(self.game.path+"/tmp/")
filecopy("./file/CTFILE.txt", self.game.path+"/tmp/CTFILE.txt")
filecopy("./file/lpar-default.txt", self.game.path + "/tmp/lpar-default.txt")
filecopy(f"./file/lecode-{self.game.region}.bin", self.game.path + f"/tmp/lecode-{self.game.region}.bin")
subprocess.run(
["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.original_region}.bin", "-od",
f"./files/rel/lecode-{self.original_region}.bin", "--track-dir", "./files/Race/Course/",
["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.game.region}.bin", "-od",
f"./files/rel/lecode-{self.game.region}.bin", "--track-dir", "./files/Race/Course/",
"--move-tracks", "./files/Race/Course/", "--le-define", "./tmp/CTFILE.txt", "--lpar",
"./tmp/lpar-default.txt", "--overwrite"],
creationflags=CREATE_NO_WINDOW, cwd=self.path_mkwf, check=True, stdout=subprocess.PIPE)
creationflags=CREATE_NO_WINDOW, cwd=self.game.path, check=True, stdout=subprocess.PIPE)
shutil.rmtree(self.path_mkwf + "/tmp/")
shutil.rmtree(self.game.path + "/tmp/")
outputformat = self.stringvar_game_format.get()
self.Progress(statut=self.translate("Converting to", " ", outputformat), add=1)
if outputformat in ["ISO", "WBFS", "CISO"]:
self.path_mkwf_format = os.path.realpath(self.path_mkwf + "/../MKWFaraphel." + outputformat.lower())
subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.path_mkwf), "--DEST",
get_nodir(self.path_mkwf_format), f"--{outputformat.lower()}", "--overwrite"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf),
path_game_format: str = os.path.realpath(self.game.path + "/../MKWFaraphel." + outputformat.lower())
subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.game.path), "--DEST",
get_nodir(path_game_format), f"--{outputformat.lower()}", "--overwrite"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(path_game_format),
check=True, stdout=subprocess.PIPE)
shutil.rmtree(self.path_mkwf)
shutil.rmtree(self.game.path)
self.game.path = path_game_format
self.Progress(statut=self.translate("Changing game's ID"), add=1)
subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.path_mkwf_format), "--id",
f"RMC{self.original_region_ID}60", "--name", f"Mario Kart Wii Faraphel {self.VERSION}",
"--modify", "ALL"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf_format),
subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.game.path), "--id",
f"RMC{self.game.region_ID}60", "--name",
f"Mario Kart Wii Faraphel {self.ctconfig.version}", "--modify", "ALL"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
check=True, stdout=subprocess.PIPE)
messagebox.showinfo(self.translate("End"), self.translate("The mod has been installed !"))

View file

@ -11,6 +11,9 @@ default_option = {
"process_track": 8
}
with open("./translation.json", encoding="utf-8") as f:
translation_dict = json.load(f)
def change_option(self, option, value, restart=False):
if type(value) in [str, int, bool]: self.option[option] = value

View file

@ -8,7 +8,7 @@ from .definition import *
def patch_bmg(self, gamefile): # gamefile est le fichier .szs trouvé dans le /files/Scene/UI/ du jeu
try:
NINTENDO_CWF_REPLACE = "Wiimmfi"
MAINMENU_REPLACE = f"MKWFaraphel {self.VERSION}"
MAINMENU_REPLACE = f"MKWFaraphel {self.ctconfig.version}"
menu_replacement = {
"CWF de Nintendo": NINTENDO_CWF_REPLACE,
"Wi-Fi Nintendo": NINTENDO_CWF_REPLACE,

View file

@ -1,49 +0,0 @@
from PIL import Image, ImageFont, ImageDraw
import json
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)
cup_number = len(config["cup"]) + math.ceil(len(config["tracks_list"]) / 4)
ct_icon = Image.new("RGBA", (128, 128 * (cup_number + 2)))
files = ["left", "right"]
files.extend(config["cup"].keys())
files.extend(["_"] * ((len(config["tracks_list"]) // 4) + 1))
for i, id in enumerate(files):
cup_icon = get_cup_icon(i)
ct_icon.paste(cup_icon, (0, i * 128))
ct_icon.save("./file/ct_icons.tpl.png")
except:
self.log_error()

View file

@ -9,23 +9,26 @@ def patch_file(self):
try:
if not(os.path.exists("./file/Track-WU8/")): os.makedirs("./file/Track-WU8/")
with open("./convert_file.json") as f: fc = json.load(f)
max_step = len(fc["img"]) + self.TOTAL_TRACK + 3 + len("EGFIS")
max_step = len(fc["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS")
self.Progress(show=True, indeter=False, statut=self.translate("Converting files"), max=max_step, step=0)
self.Progress(statut=self.translate("Configurating LE-CODE"), add=1)
self.create_lecode_config()
self.ctconfig.create_ctfile()
self.Progress(statut=self.translate("Creating ct_icon.png"), add=1)
self.patch_ct_icon()
ct_icon = self.ctconfig.get_cticon()
ct_icon.save("./file/ct_icons.tpl.png")
self.Progress(statut=self.translate("Creating descriptive images"), add=1)
self.patch_img_desc()
self.patch_image(fc)
for file in glob.glob(self.path_mkwf+"/files/Scene/UI/MenuSingle_?.szs"): self.patch_bmg(file)
for file in glob.glob(self.game.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()
if self.patch_track() != 0: return
self.button_install_mod.grid(row=2, column=1, columnspan=2, sticky="NEWS")
self.button_install_mod.config(text=self.translate("Install mod", " (v", self.VERSION, ")"))
self.button_install_mod.config(text=self.translate("Install mod", " (v", self.ctconfig.version, ")"))
except: self.log_error()
finally: self.Progress(show=False)

View file

@ -2,69 +2,18 @@ from .definition import *
from tkinter import messagebox
import subprocess
import shutil
import json
import os
def get_trackname(self, track, color=False):
hl_prefix, hl_suffix = "", ""
if color:
if track.get("since_version") == self.stringvar_mark_track_from_version.get():
hl_prefix, hl_suffix = "\\\\c{blue1}", "\\\\c{off}"
name = track["name"]
name = hl_prefix + name + hl_suffix
if "prefix" in track:
prefix = track["prefix"]
if color:
if prefix in trackname_color:
prefix = trackname_color[prefix]
name = prefix + " " + name
if "suffix" in track:
suffix = track["suffix"]
if color:
if suffix in trackname_color:
suffix = trackname_color[suffix]
name = name + " (" + suffix + ")"
return name
def get_trackctname(self, *args, **kwargs):
return self.get_trackname(*args, **kwargs).replace("_", "")
def load_ct_config(self):
tracks = []
with open("./ct_config.json", encoding="utf-8") as f: ctconfig = json.load(f)
for cup in ctconfig["cup"].values(): # defined order tracks
if not (cup["locked"]): tracks.extend(cup["courses"].values())
tracks.extend(ctconfig["tracks_list"]) # unordered tracks
self.TRACKS = [dict(t) for t in {tuple(d.items()) for d in tracks}] # removing duplicate
self.TOTAL_TRACK = len(tracks)
self.VERSION = ctconfig["version"]
self.ALL_VERSION = []
for track in self.TRACKS:
if not track.get("since_version") in self.ALL_VERSION:
self.ALL_VERSION.append(track["since_version"])
self.ALL_VERSION.sort()
def patch_autoadd(self):
if os.path.exists("./file/auto-add"): shutil.rmtree("./file/auto-add")
if not os.path.exists(self.path_mkwf + "/tmp/"): os.makedirs(self.path_mkwf + "/tmp/")
subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.path_mkwf) + "/files/Race/Course/",
"--DEST", get_nodir(self.path_mkwf) + "/tmp/auto-add/"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf),
if not os.path.exists(self.game.path + "/tmp/"): os.makedirs(self.game.path + "/tmp/")
subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.game.path) + "/files/Race/Course/",
"--DEST", get_nodir(self.game.path) + "/tmp/auto-add/"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
check=True, stdout=subprocess.PIPE)
shutil.move(self.path_mkwf + "/tmp/auto-add/", "./file/auto-add/")
shutil.rmtree(self.path_mkwf + "/tmp/")
shutil.move(self.game.path + "/tmp/auto-add/", "./file/auto-add/")
shutil.rmtree(self.game.path + "/tmp/")
def patch_track(self):
@ -73,20 +22,21 @@ def patch_track(self):
error_count, error_max = 0, 3
def add_process(track):
track_file = self.get_trackname(track=track)
nonlocal error_count, error_max, process_list
track_file = track.get_track_name()
total_track = len(self.ctconfig.all_tracks)
process_list[track_file] = None # Used for
self.Progress(statut=self.translate("Converting tracks", f"\n({i + 1}/{self.TOTAL_TRACK})\n",
process_list[track_file] = None # Used for showing track in progress even if there's no process
self.Progress(statut=self.translate("Converting tracks", f"\n({i + 1}/{total_track})\n",
"\n".join(process_list.keys())), add=1)
for _track in [get_track_szs(track_file), get_track_wu8(track_file)]:
for _track in [track.file_szs, track.file_wu8]:
if os.path.exists(_track):
if os.path.getsize(_track) < 1000: # File under this size are corrupted
os.remove(_track)
while True:
download_returncode = self.get_github_file(get_track_wu8(track_file))
download_returncode = self.get_github_file(track.file_wu8)
if download_returncode == -1: # can't download
error_count += 1
if error_count > error_max: # Too much track wasn't correctly converted
@ -100,9 +50,9 @@ def patch_track(self):
f" ({error_count} / {error_max})"))
elif download_returncode == 2: break # if download is disabled, don't check sha1
if "sha1" in track:
if track.sha1:
if not self.boolvar_dont_check_track_sha1.get():
if not self.check_track_sha1(get_track_wu8(track_file), track["sha1"]) == 0: # La course est correcte
if not track.check_sha1(): # Check si le sha1 du fichier est le bon
error_count += 1
if error_count > error_max: # Too much track wasn't correctly converted
messagebox.showerror(
@ -113,18 +63,14 @@ def patch_track(self):
break
if not (os.path.exists(
get_track_szs(track_file))) or download_returncode == 3: # returncode 3 is track has been updated
if os.path.exists(get_track_wu8(track_file)):
process_list[track_file] = subprocess.Popen([
"./tools/szs/wszst", "NORMALIZE", get_track_wu8(track_file), "--DEST",
"./file/Track/%N.szs", "--szs", "--overwrite", "--autoadd-path",
"./file/auto-add/"], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE)
if not (os.path.exists(track.file_szs)) or download_returncode == 3: # returncode 3 is track has been updated
if os.path.exists(track.file_wu8):
process_list[track_file] = track.convert_wu8_to_szs()
else:
messagebox.showerror(self.translate("Error"),
self.translate("Can't convert track.\nEnable track download and retry."))
return -1
elif self.boolvar_del_track_after_conv.get(): os.remove(get_track_wu8(track_file))
elif self.boolvar_del_track_after_conv.get(): os.remove(track.file_wu8)
return 0
def clean_process():
@ -138,7 +84,7 @@ def patch_track(self):
process_list.pop(track_file)
stderr = process.stderr.read()
if b"wszst: ERROR" in stderr: # Error occured
os.remove(get_track_szs(track_file))
os.remove(track.file_szs)
error_count += 1
if error_count > error_max: # Too much track wasn't correctly converted
messagebox.showerror(
@ -152,7 +98,7 @@ def patch_track(self):
"do not have been properly converted.",
f" ({error_count} / {error_max})"))
else:
if self.boolvar_del_track_after_conv.get(): os.remove(get_track_wu8(track_file))
if self.boolvar_del_track_after_conv.get(): os.remove(track.file_wu8)
else:
process_list.pop(track_file)
if not(any(process_list.values())): return 1 # si il n'y a plus de processus
@ -160,7 +106,7 @@ def patch_track(self):
if len(process_list): return 1
else: return 0
for i, track in enumerate(self.TRACKS):
for i, track in enumerate(self.ctconfig.all_tracks):
while True:
if len(process_list) < max_process:
returncode = add_process(track)

View file

@ -1,4 +1,4 @@
from .definition import translation_dict
from .option import translation_dict
def translate(self, *texts, lang=None):

View file

@ -13,8 +13,9 @@ def sha1(file):
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/"):
output_format: str = "szs", autoadd_path: str = "./file/auto-add/", use_popen: bool = False):
"""
:param use_popen: True if you want to use Popen to convert
:param src_file: source file
:param dest_dir: destination directory
:param dest_name: destination filename (%N mean same name as src_file)
@ -22,13 +23,31 @@ def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = "
:param autoadd_path: path of the auto-add directory
:return: 0
"""
subprocess.run([
if use_popen: cmd_process = subprocess.Popen
else: cmd_process = subprocess.run
return cmd_process([
"./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
def extract(file: str, dest_dir: str):
subprocess.call(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))
subprocess.run(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))
def create(file: str):
pass
def wstrt_patch(file: str):
pass
def wlect_patch(file: str,
lecode_file: str = f"./files/rel/lecode-PAL.bin",
game_track_path: str = "./files/Race/Course/",
move_track_path: str = "./files/Race/Course/",
ctfile_path: str = "./tmp/CTFILE.txt",
lpar_path: str = "./tmp/lpar-default.txt"):
pass

View file

@ -14,6 +14,7 @@
"Wii game": "Jeu Wii",
"Error": "Erreur",
"The file path in invalid": "Le chemin de fichier est invalide",
"This game's format is invalid": "Le format du jeu est invalide",
"Warning": "Attention",
"This directory will be overwritten if you install the mod !\nAre you sure you want to use it ?": "Ce dossier sera écrasé si vous installer le mod !\nÊtes-vous sûr de vouloir l'utiliser ?",
"Extracting the game...": "Extraction du jeu...",