mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-06 04:38:29 +02:00
implemented a very experimental function for packs
This commit is contained in:
parent
fd997719b3
commit
6042ca441a
8 changed files with 120 additions and 146 deletions
|
@ -7,28 +7,6 @@ from source.Cup import Cup
|
||||||
from source.Track import Track, HiddenTrackAttr
|
from source.Track import Track, HiddenTrackAttr
|
||||||
|
|
||||||
|
|
||||||
def get_cup_icon(cup_id: [str, int], font_path: str = "./file/SuperMario256.ttf",
|
|
||||||
cup_icon_dir: str = "./file/cup_icon") -> Image:
|
|
||||||
"""
|
|
||||||
:param cup_id: id of the cup
|
|
||||||
:param cup_icon_dir: directory to cup icon
|
|
||||||
:param font_path: path to the font used to generate icon
|
|
||||||
: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(font_path, 90)
|
|
||||||
draw.text((4, 4), "CT", (255, 165, 0), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
|
|
||||||
font = ImageFont.truetype(font_path, 60)
|
|
||||||
draw.text((5, 80), "%03i" % cup_id, (255, 165, 0), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
|
|
||||||
|
|
||||||
return cup_icon
|
|
||||||
|
|
||||||
|
|
||||||
class CT_Config:
|
class CT_Config:
|
||||||
def __init__(self, version: str = None, name: str = None, nickname: str = None,
|
def __init__(self, version: str = None, name: str = None, nickname: str = None,
|
||||||
game_variant: str = "01", gui=None, region: int = None, cheat_region: int = None,
|
game_variant: str = "01", gui=None, region: int = None, cheat_region: int = None,
|
||||||
|
@ -117,6 +95,27 @@ class CT_Config:
|
||||||
ctfile.write(cup.get_ctfile_cup(race=False, **kwargs))
|
ctfile.write(cup.get_ctfile_cup(race=False, **kwargs))
|
||||||
rctfile.write(cup.get_ctfile_cup(race=True, **kwargs))
|
rctfile.write(cup.get_ctfile_cup(race=True, **kwargs))
|
||||||
|
|
||||||
|
def get_cup_icon(self, cup_id: [str, int], font_path: str = "./assets/SuperMario256.ttf",
|
||||||
|
cup_icon_dir: str = "./file/cup_icon") -> Image:
|
||||||
|
"""
|
||||||
|
:param cup_id: id of the cup
|
||||||
|
:param cup_icon_dir: directory to cup icon
|
||||||
|
:param font_path: path to the font used to generate icon
|
||||||
|
: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(font_path, 90)
|
||||||
|
draw.text((4, 4), "CT", (255, 165, 0), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
|
||||||
|
font = ImageFont.truetype(font_path, 60)
|
||||||
|
draw.text((5, 80), "%03i" % cup_id, (255, 165, 0), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
|
||||||
|
|
||||||
|
return cup_icon
|
||||||
|
|
||||||
def get_cticon(self) -> Image:
|
def get_cticon(self) -> Image:
|
||||||
"""
|
"""
|
||||||
get all cup icon into a single image
|
get all cup icon into a single image
|
||||||
|
@ -133,7 +132,7 @@ class CT_Config:
|
||||||
|
|
||||||
for index, cup_id in enumerate(icon_files):
|
for index, cup_id in enumerate(icon_files):
|
||||||
# index is a number, id can be string or number ("left", 0, 12, ...)
|
# index is a number, id can be string or number ("left", 0, 12, ...)
|
||||||
cup_icon = get_cup_icon(cup_id)
|
cup_icon = self.get_cup_icon(cup_id, cup_icon_dir=self.pack_path+"/file/cup_icon/")
|
||||||
ct_icon.paste(cup_icon, (0, index * CT_ICON_WIDTH))
|
ct_icon.paste(cup_icon, (0, index * CT_ICON_WIDTH))
|
||||||
|
|
||||||
return ct_icon
|
return ct_icon
|
||||||
|
@ -159,19 +158,20 @@ class CT_Config:
|
||||||
self.unordered_tracks = []
|
self.unordered_tracks = []
|
||||||
self.all_tracks = []
|
self.all_tracks = []
|
||||||
|
|
||||||
|
self.pack_path = pack_path
|
||||||
|
|
||||||
# default track
|
# default track
|
||||||
self.default_track = Track()
|
self.default_track = Track(track_wu8_dir=f"{self.pack_path}/file/Track-WU8/")
|
||||||
if "default_track" in ctconfig_json: self.default_track.load_from_json(ctconfig_json["default_track"])
|
if "default_track" in ctconfig_json: self.default_track.load_from_json(ctconfig_json["default_track"])
|
||||||
|
|
||||||
for cup_json in ctconfig_json["cup"] if "cup" in ctconfig_json else []: # tracks with defined order
|
for cup_json in ctconfig_json["cup"] if "cup" in ctconfig_json else []: # tracks with defined order
|
||||||
cup = Cup(default_track=self.default_track)
|
cup = Cup(default_track=self.default_track)
|
||||||
cup.load_from_json(cup_json)
|
cup.load_from_json(cup_json)
|
||||||
if not cup.locked: # locked cup are not useful (they are original track or random track)
|
self.ordered_cups.append(cup)
|
||||||
self.ordered_cups.append(cup)
|
self.all_tracks.extend(cup.tracks)
|
||||||
self.all_tracks.extend(cup.tracks)
|
|
||||||
|
|
||||||
for track_json in ctconfig_json["tracks_list"] if "tracks_list" in ctconfig_json else []: # unordered tracks
|
for track_json in ctconfig_json["tracks_list"] if "tracks_list" in ctconfig_json else []: # unordered tracks
|
||||||
track = Track()
|
track = Track(track_wu8_dir=f"{self.pack_path}/file/Track-WU8/")
|
||||||
track.load_from_json(track_json)
|
track.load_from_json(track_json)
|
||||||
self.unordered_tracks.append(track)
|
self.unordered_tracks.append(track)
|
||||||
self.all_tracks.append(track)
|
self.all_tracks.append(track)
|
||||||
|
@ -182,7 +182,7 @@ class CT_Config:
|
||||||
self.nickname = ctconfig_json["nickname"] if "nickname" in ctconfig_json else self.name
|
self.nickname = ctconfig_json["nickname"] if "nickname" in ctconfig_json else self.name
|
||||||
if "game_variant" in ctconfig_json: self.game_variant = ctconfig_json["game_variant"]
|
if "game_variant" in ctconfig_json: self.game_variant = ctconfig_json["game_variant"]
|
||||||
|
|
||||||
for param in ["region", "cheat_region", "tags_color", "prefix_list", "suffix_list", "tag_retro", "pack_path"]:
|
for param in ["region", "cheat_region", "tags_color", "prefix_list", "suffix_list", "tag_retro"]:
|
||||||
setattr(self, param, ctconfig_json.get(param))
|
setattr(self, param, ctconfig_json.get(param))
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
|
@ -9,7 +9,6 @@ class Cup:
|
||||||
track2: Track = None,
|
track2: Track = None,
|
||||||
track3: Track = None,
|
track3: Track = None,
|
||||||
track4: Track = None,
|
track4: Track = None,
|
||||||
locked: bool = False,
|
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
class of a cup
|
class of a cup
|
||||||
|
@ -18,13 +17,11 @@ class Cup:
|
||||||
:param track2: second track
|
:param track2: second track
|
||||||
:param track3: third track
|
:param track3: third track
|
||||||
:param track4: fourth track
|
:param track4: fourth track
|
||||||
:param locked: is the track locked (used to load ctconfig in CT_Config)
|
|
||||||
:param args: other args that I could add in the future
|
:param args: other args that I could add in the future
|
||||||
:param kwargs: other kwargs that I could add in the future
|
:param kwargs: other kwargs that I could add in the future
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.locked = locked
|
|
||||||
self.tracks = [
|
self.tracks = [
|
||||||
track1 if track1 else default_track.copy(),
|
track1 if track1 else default_track.copy(),
|
||||||
track2 if track2 else default_track.copy(),
|
track2 if track2 else default_track.copy(),
|
||||||
|
@ -51,7 +48,7 @@ class Cup:
|
||||||
for key, value in cup.items(): # load all value in the json as class attribute
|
for key, value in cup.items(): # load all value in the json as class attribute
|
||||||
if key == "tracks": # if the key is tracks
|
if key == "tracks": # if the key is tracks
|
||||||
for i, track_json in enumerate(value): # load all tracks from their json
|
for i, track_json in enumerate(value): # load all tracks from their json
|
||||||
self.tracks[int(i)].load_from_json(track_json)
|
self.tracks[i].load_from_json(track_json)
|
||||||
else:
|
else:
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
|
@ -213,14 +213,14 @@ class Game:
|
||||||
szs_extract_path = path + ".d"
|
szs_extract_path = path + ".d"
|
||||||
if os.path.exists(szs_extract_path + subpath):
|
if os.path.exists(szs_extract_path + subpath):
|
||||||
if subpath[-1] == "/":
|
if subpath[-1] == "/":
|
||||||
shutil.copyfile(f"./file/{file}", szs_extract_path + subpath + file)
|
shutil.copyfile(f"{self.ctconfig.pack_path}/file/{file}", szs_extract_path + subpath + file)
|
||||||
else:
|
else:
|
||||||
shutil.copyfile(f"./file/{file}", szs_extract_path + subpath)
|
shutil.copyfile(f"{self.ctconfig.pack_path}/file/{file}", szs_extract_path + subpath)
|
||||||
|
|
||||||
elif path[-1] == "/":
|
elif path[-1] == "/":
|
||||||
shutil.copyfile(f"./file/{file}", path + file)
|
shutil.copyfile(f"{self.ctconfig.pack_path}/file/{file}", path + file)
|
||||||
else:
|
else:
|
||||||
shutil.copyfile(f"./file/{file}", path)
|
shutil.copyfile(f"{self.ctconfig.pack_path}/file/{file}", path)
|
||||||
|
|
||||||
for fp in fs:
|
for fp in fs:
|
||||||
for f in glob.glob(self.path + "/files/" + fp, recursive=True):
|
for f in glob.glob(self.path + "/files/" + fp, recursive=True):
|
||||||
|
@ -282,10 +282,11 @@ class Game:
|
||||||
"""
|
"""
|
||||||
self.gui.progress(statut=self.gui.translate("Patch lecode.bin"), add=1)
|
self.gui.progress(statut=self.gui.translate("Patch lecode.bin"), add=1)
|
||||||
|
|
||||||
lpar_path = "./file/lpar-debug.txt" if self.gui.boolvar_use_debug_mode.get() else "./file/lpar-default.txt"
|
lpar_path = f"{self.ctconfig.pack_path}/file/lpar-debug.txt" \
|
||||||
|
if self.gui.boolvar_use_debug_mode.get() else f"{self.ctconfig.pack_path}/file/lpar-default.txt"
|
||||||
|
|
||||||
lec.patch(
|
lec.patch(
|
||||||
lecode_file=f"./file/lecode-{self.region}.bin",
|
lecode_file=f"{self.ctconfig.pack_path}/file/lecode-{self.region}.bin",
|
||||||
dest_lecode_file=f"{self.path}/files/rel/lecode-{self.region}.bin",
|
dest_lecode_file=f"{self.path}/files/rel/lecode-{self.region}.bin",
|
||||||
game_track_path=f"{self.path}/files/Race/Course/",
|
game_track_path=f"{self.path}/files/Race/Course/",
|
||||||
copy_track_paths=[f"./file/Track/"],
|
copy_track_paths=[f"./file/Track/"],
|
||||||
|
@ -422,13 +423,12 @@ class Game:
|
||||||
:param bmg_language: language of the bmg file
|
:param bmg_language: language of the bmg file
|
||||||
:return: the replaced bmg file
|
:return: the replaced bmg file
|
||||||
"""
|
"""
|
||||||
with open("./file_process.json", encoding="utf8") as fp_file:
|
with open(f"{self.ctconfig.pack_path}/file_process.json", encoding="utf8") as fp_file:
|
||||||
file_process = json.load(fp_file)
|
file_process = json.load(fp_file)
|
||||||
|
|
||||||
for bmg_process in file_process["bmg"]:
|
for bmg_process in file_process["bmg"]:
|
||||||
if "language" in bmg_process:
|
if "language" in bmg_process and bmg_language not in bmg_process["language"]:
|
||||||
if bmg_language not in bmg_process["language"]:
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
for data, data_replacement in bmg_process["data"].items():
|
for data, data_replacement in bmg_process["data"].items():
|
||||||
for key, replacement in bmg_replacement.items():
|
for key, replacement in bmg_replacement.items():
|
||||||
|
@ -462,17 +462,18 @@ class Game:
|
||||||
bmg.encode(file)
|
bmg.encode(file)
|
||||||
os.remove(file)
|
os.remove(file)
|
||||||
|
|
||||||
save_bmg(f"./file/Menu_{bmglang}.txt", process_bmg_replacement(bmgmenu, bmglang))
|
save_bmg(f"{self.ctconfig.pack_path}/file/Menu_{bmglang}.txt", process_bmg_replacement(bmgmenu, bmglang))
|
||||||
save_bmg(f"./file/Common_{bmglang}.txt", process_bmg_replacement(bmgcommon, bmglang))
|
save_bmg(f"{self.ctconfig.pack_path}/file/Common_{bmglang}.txt", process_bmg_replacement(bmgcommon, bmglang))
|
||||||
save_bmg(f"./file/Common_R{bmglang}.txt", process_bmg_replacement(rbmgcommon, bmglang))
|
save_bmg(f"{self.ctconfig.pack_path}/file/Common_R{bmglang}.txt", process_bmg_replacement(rbmgcommon, bmglang))
|
||||||
|
|
||||||
def patch_file(self):
|
def patch_file(self):
|
||||||
"""
|
"""
|
||||||
Prepare all files to install the mod (track, bmg text, descriptive image, ...)
|
Prepare all files to install the mod (track, bmg text, descriptive image, ...)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if not (os.path.exists("./file/Track-WU8/")): os.makedirs("./file/Track-WU8/")
|
os.makedirs(f"{self.ctconfig.pack_path}/file/Track-WU8/", exist_ok=True)
|
||||||
with open("./file_process.json", encoding="utf8") as fp_file:
|
|
||||||
|
with open(f"{self.ctconfig.pack_path}/file_process.json", encoding="utf8") as fp_file:
|
||||||
file_process = json.load(fp_file)
|
file_process = json.load(fp_file)
|
||||||
max_step = len(file_process["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS")
|
max_step = len(file_process["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS")
|
||||||
|
|
||||||
|
@ -486,10 +487,13 @@ class Game:
|
||||||
|
|
||||||
self.gui.progress(statut=self.gui.translate("Creating ct_icon.png"), add=1)
|
self.gui.progress(statut=self.gui.translate("Creating ct_icon.png"), add=1)
|
||||||
ct_icon = self.ctconfig.get_cticon()
|
ct_icon = self.ctconfig.get_cticon()
|
||||||
ct_icon.save("./file/ct_icons.tpl.png")
|
ct_icon.save(f"{self.ctconfig.pack_path}/file/ct_icons.tpl.png")
|
||||||
|
|
||||||
self.gui.progress(statut=self.gui.translate("Creating descriptive images"), add=1)
|
self.gui.progress(statut=self.gui.translate("Creating descriptive images"), add=1)
|
||||||
self.patch_img_desc()
|
self.patch_img_desc(
|
||||||
|
img_desc_path=self.ctconfig.pack_path+"/file/img_desc/",
|
||||||
|
dest_dir=self.ctconfig.pack_path+"/file/"
|
||||||
|
)
|
||||||
self.patch_image(file_process["img"])
|
self.patch_image(file_process["img"])
|
||||||
for file in glob.glob(self.path + "/files/Scene/UI/MenuSingle_?.szs"): self.patch_bmg(file)
|
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.
|
# MenuSingle could be any other file, Common and Menu are all the same in all other files.
|
||||||
|
@ -511,7 +515,12 @@ class Game:
|
||||||
for i, file in enumerate(fp_img):
|
for i, file in enumerate(fp_img):
|
||||||
self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fp_img)}) {file}",
|
self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fp_img)}) {file}",
|
||||||
add=1)
|
add=1)
|
||||||
img.encode(file="./file/" + file, format=fp_img[file])
|
# TODO: IMG DESC AND THIS PART REALLY NEED A REWRITE !
|
||||||
|
|
||||||
|
img.encode(
|
||||||
|
file=f"{self.ctconfig.pack_path}/file/{file}",
|
||||||
|
format=fp_img[file]
|
||||||
|
)
|
||||||
|
|
||||||
def patch_img_desc(self, img_desc_path: str = "./file/img_desc/", dest_dir: str = "./file/") -> None:
|
def patch_img_desc(self, img_desc_path: str = "./file/img_desc/", dest_dir: str = "./file/") -> None:
|
||||||
"""
|
"""
|
||||||
|
|
124
source/Gui.py
124
source/Gui.py
|
@ -7,7 +7,6 @@ import requests
|
||||||
import zipfile
|
import zipfile
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
|
|
||||||
from source.Game import Game, RomAlreadyPatched, InvalidGamePath, InvalidFormat
|
from source.Game import Game, RomAlreadyPatched, InvalidGamePath, InvalidFormat
|
||||||
from source.Option import Option
|
from source.Option import Option
|
||||||
|
@ -25,9 +24,10 @@ class Gui:
|
||||||
Initialize program Gui
|
Initialize program Gui
|
||||||
"""
|
"""
|
||||||
self.root = Tk()
|
self.root = Tk()
|
||||||
|
self.root.resizable(False, False)
|
||||||
|
self.root.iconbitmap(bitmap="./icon.ico")
|
||||||
|
|
||||||
self.option = Option()
|
self.option = Option().load_from_file("./option.json")
|
||||||
self.option.load_from_file("./option.json")
|
|
||||||
self.game = Game(gui=self)
|
self.game = Game(gui=self)
|
||||||
|
|
||||||
self.menu_bar = None
|
self.menu_bar = None
|
||||||
|
@ -47,42 +47,35 @@ class Gui:
|
||||||
self.boolvar_dont_check_for_update = BooleanVar(value=self.option.dont_check_for_update)
|
self.boolvar_dont_check_for_update = BooleanVar(value=self.option.dont_check_for_update)
|
||||||
self.intvar_process_track = IntVar(value=self.option.process_track)
|
self.intvar_process_track = IntVar(value=self.option.process_track)
|
||||||
|
|
||||||
|
self.root.title(self.translate("MKWFaraphel Installer"))
|
||||||
|
|
||||||
self.boolvar_use_1star_track = BooleanVar(value=True)
|
self.boolvar_use_1star_track = BooleanVar(value=True)
|
||||||
self.boolvar_use_2star_track = BooleanVar(value=True)
|
self.boolvar_use_2star_track = BooleanVar(value=True)
|
||||||
self.boolvar_use_3star_track = BooleanVar(value=True)
|
self.boolvar_use_3star_track = BooleanVar(value=True)
|
||||||
|
|
||||||
self.stringvar_mark_track_from_version = StringVar(value="None")
|
self.stringvar_mark_track_from_version = StringVar(value="None")
|
||||||
self.stringvar_sort_track_by = StringVar(value="name")
|
self.stringvar_sort_track_by = StringVar(value="name")
|
||||||
|
|
||||||
self.boolvar_use_debug_mode = BooleanVar(value=False)
|
self.boolvar_use_debug_mode = BooleanVar(value=False)
|
||||||
self.boolvar_force_unofficial_mode = BooleanVar(value=False)
|
self.boolvar_force_unofficial_mode = BooleanVar(value=False)
|
||||||
|
|
||||||
self.stringvar_mystuff_folder = StringVar(value=None)
|
self.stringvar_mystuff_folder = StringVar(value=None)
|
||||||
self.stringvar_mystuff_music_folder = StringVar(value=None)
|
|
||||||
self.stringvar_mystuff_vehicle_folder = StringVar(value=None)
|
|
||||||
self.stringvar_mystuff_character_folder = StringVar(value=None)
|
|
||||||
self.stringvar_mystuff_original_track_folder = StringVar(value=None)
|
|
||||||
|
|
||||||
self.root.title(self.translate("MKWFaraphel Installer"))
|
|
||||||
self.root.resizable(False, False)
|
|
||||||
self.root.iconbitmap(bitmap="./icon.ico")
|
|
||||||
|
|
||||||
if not self.boolvar_dont_check_for_update.get(): self.check_update()
|
if not self.boolvar_dont_check_for_update.get(): self.check_update()
|
||||||
|
|
||||||
self.init_gui()
|
# GUI
|
||||||
self.init_menu()
|
# Mod selector
|
||||||
|
|
||||||
def init_gui(self) -> None:
|
|
||||||
self.frame_ctconfig = LabelFrame(self.root, text=self.translate("Mod"))
|
self.frame_ctconfig = LabelFrame(self.root, text=self.translate("Mod"))
|
||||||
self.frame_ctconfig.grid(row=1, column=1, sticky="NWS")
|
self.frame_ctconfig.grid(row=1, column=1, sticky="NWS")
|
||||||
|
|
||||||
self.combobox_ctconfig_path = ttk.Combobox(
|
self.combobox_ctconfig_path = ttk.Combobox(
|
||||||
self.frame_ctconfig,
|
self.frame_ctconfig,
|
||||||
values=self.available_packs,
|
values=self.available_packs,
|
||||||
textvariable=self.stringvar_ctconfig
|
textvariable=self.stringvar_ctconfig,
|
||||||
|
width=30
|
||||||
)
|
)
|
||||||
self.combobox_ctconfig_path.grid(row=1, column=1, sticky="NEWS", columnspan=2)
|
self.combobox_ctconfig_path.grid(row=1, column=1, sticky="NEWS", columnspan=2)
|
||||||
self.combobox_ctconfig_path.bind("<<ComboboxSelected>>", lambda x=None: self.init_menu())
|
self.combobox_ctconfig_path.bind("<<ComboboxSelected>>", lambda x=None: self.reload_ctconfig())
|
||||||
|
self.reload_ctconfig()
|
||||||
|
|
||||||
# Jeu
|
# Jeu
|
||||||
self.frame_game_path = LabelFrame(self.root, text=self.translate("Original game"))
|
self.frame_game_path = LabelFrame(self.root, text=self.translate("Original game"))
|
||||||
|
@ -136,21 +129,22 @@ class Gui:
|
||||||
self.game.patch_file()
|
self.game.patch_file()
|
||||||
self.game.install_mod()
|
self.game.install_mod()
|
||||||
|
|
||||||
self.button_do_everything = Button(self.frame_game_path_action, text=self.translate("Install mod"),
|
self.button_do_everything = Button(
|
||||||
relief=RIDGE, command=do_everything)
|
self.frame_game_path_action,
|
||||||
|
text=self.translate("Install mod"),
|
||||||
|
relief=RIDGE,
|
||||||
|
command=do_everything
|
||||||
|
)
|
||||||
self.button_do_everything.grid(row=1, column=1, columnspan=2, sticky="NEWS")
|
self.button_do_everything.grid(row=1, column=1, columnspan=2, sticky="NEWS")
|
||||||
|
|
||||||
self.progressbar = ttk.Progressbar(self.root)
|
self.progressbar = ttk.Progressbar(self.root)
|
||||||
self.progresslabel = Label(self.root)
|
self.progresslabel = Label(self.root)
|
||||||
|
|
||||||
def init_menu(self) -> None:
|
|
||||||
if self.menu_bar: self.menu_bar.destroy()
|
if self.menu_bar: self.menu_bar.destroy()
|
||||||
self.menu_bar = Menu(self.root)
|
self.menu_bar = Menu(self.root)
|
||||||
self.root.config(menu=self.menu_bar)
|
self.root.config(menu=self.menu_bar)
|
||||||
|
|
||||||
self.game.ctconfig.load_ctconfig_file(ctconfig_file=self.get_ctconfig_path_pack(self.stringvar_ctconfig.get()))
|
|
||||||
track_attr_possibilities = self.game.ctconfig.get_all_track_possibilities()
|
|
||||||
|
|
||||||
# LANGUAGE MENU
|
# LANGUAGE MENU
|
||||||
self.menu_language = Menu(self.menu_bar, tearoff=0)
|
self.menu_language = Menu(self.menu_bar, tearoff=0)
|
||||||
self.menu_bar.add_cascade(label=self.translate("Language"), menu=self.menu_language)
|
self.menu_bar.add_cascade(label=self.translate("Language"), menu=self.menu_language)
|
||||||
|
@ -195,50 +189,6 @@ class Gui:
|
||||||
command=lambda: self.option.edit("format", "WBFS")
|
command=lambda: self.option.edit("format", "WBFS")
|
||||||
)
|
)
|
||||||
|
|
||||||
# TRACK CONFIGURATION MENU
|
|
||||||
self.menu_trackconfiguration = Menu(self.menu_bar, tearoff=0)
|
|
||||||
self.menu_bar.add_cascade(label=self.translate("Track configuration"), menu=self.menu_trackconfiguration)
|
|
||||||
|
|
||||||
# sort track
|
|
||||||
self.menu_sort_track_by = Menu(self.menu_trackconfiguration, tearoff=0)
|
|
||||||
self.menu_trackconfiguration.add_cascade(label=self.translate("Sort track"), menu=self.menu_sort_track_by)
|
|
||||||
for param in track_attr_possibilities:
|
|
||||||
self.menu_sort_track_by.add_radiobutton(
|
|
||||||
label=param.title(),
|
|
||||||
variable=self.stringvar_sort_track_by,
|
|
||||||
value=param
|
|
||||||
)
|
|
||||||
|
|
||||||
# select track
|
|
||||||
self.menu_trackselection = Menu(self.menu_trackconfiguration, tearoff=0)
|
|
||||||
self.menu_trackconfiguration.add_cascade(label=self.translate("Select track"), menu=self.menu_trackselection)
|
|
||||||
self.menu_trackselection_param = {}
|
|
||||||
|
|
||||||
self.menu_trackhighlight = Menu(self.menu_trackconfiguration, tearoff=0)
|
|
||||||
self.menu_trackconfiguration.add_cascade(label=self.translate("Highlight track"), menu=self.menu_trackhighlight)
|
|
||||||
self.menu_trackhighlight_param = {}
|
|
||||||
|
|
||||||
for param, values in track_attr_possibilities.items():
|
|
||||||
for menu_param, menu in [
|
|
||||||
(self.menu_trackselection_param, self.menu_trackselection),
|
|
||||||
(self.menu_trackhighlight_param, self.menu_trackhighlight)
|
|
||||||
]:
|
|
||||||
menu_param[param] = {
|
|
||||||
"Menu": Menu(menu, tearoff=0),
|
|
||||||
"Var": []
|
|
||||||
}
|
|
||||||
menu.add_cascade(
|
|
||||||
label=param.title(),
|
|
||||||
menu=menu_param[param]["Menu"]
|
|
||||||
)
|
|
||||||
|
|
||||||
for value in values:
|
|
||||||
menu_param[param]["Var"].append(BooleanVar(value=True))
|
|
||||||
menu_param[param]["Menu"].add_checkbutton(
|
|
||||||
label=value,
|
|
||||||
variable=menu_param[param]["Var"][-1],
|
|
||||||
)
|
|
||||||
|
|
||||||
# ADVANCED MENU
|
# ADVANCED MENU
|
||||||
## INSTALLER PARAMETER
|
## INSTALLER PARAMETER
|
||||||
self.menu_advanced = Menu(self.menu_bar, tearoff=0)
|
self.menu_advanced = Menu(self.menu_bar, tearoff=0)
|
||||||
|
@ -286,7 +236,8 @@ class Gui:
|
||||||
## GAME PARAMETER
|
## GAME PARAMETER
|
||||||
self.menu_advanced.add_separator()
|
self.menu_advanced.add_separator()
|
||||||
|
|
||||||
self.menu_advanced.add_checkbutton(label=self.translate("Use debug mode"), variable=self.boolvar_use_debug_mode)
|
self.menu_advanced.add_checkbutton(label=self.translate("Use debug mode"),
|
||||||
|
variable=self.boolvar_use_debug_mode)
|
||||||
|
|
||||||
self.menu_mystuff = Menu(self.menu_advanced, tearoff=0)
|
self.menu_mystuff = Menu(self.menu_advanced, tearoff=0)
|
||||||
self.menu_advanced.add_cascade(label=self.translate("MyStuff"), menu=self.menu_mystuff)
|
self.menu_advanced.add_cascade(label=self.translate("MyStuff"), menu=self.menu_mystuff)
|
||||||
|
@ -303,7 +254,7 @@ class Gui:
|
||||||
|
|
||||||
self.menu_mystuff.entryconfig(index, label=self.translate(
|
self.menu_mystuff.entryconfig(index, label=self.translate(
|
||||||
"Apply", " ", label, f" ({stringvar.get()!r} ", "selected", ")")
|
"Apply", " ", label, f" ({stringvar.get()!r} ", "selected", ")")
|
||||||
)
|
)
|
||||||
|
|
||||||
_func(init=True)
|
_func(init=True)
|
||||||
self.menu_mystuff.entryconfig(index, command=_func)
|
self.menu_mystuff.entryconfig(index, command=_func)
|
||||||
|
@ -318,6 +269,11 @@ class Gui:
|
||||||
self.menu_help.add_command(label="Github Wiki", command=lambda: webbrowser.open(GITHUB_HELP_PAGE_URL))
|
self.menu_help.add_command(label="Github Wiki", command=lambda: webbrowser.open(GITHUB_HELP_PAGE_URL))
|
||||||
self.menu_help.add_command(label="Discord", command=lambda: webbrowser.open(DISCORD_URL))
|
self.menu_help.add_command(label="Discord", command=lambda: webbrowser.open(DISCORD_URL))
|
||||||
|
|
||||||
|
def reload_ctconfig(self) -> None:
|
||||||
|
self.game.ctconfig.load_ctconfig_file(
|
||||||
|
ctconfig_file=self.get_ctconfig_path_pack(self.stringvar_ctconfig.get())
|
||||||
|
)
|
||||||
|
|
||||||
def get_available_packs(self) -> list:
|
def get_available_packs(self) -> list:
|
||||||
available_packs = []
|
available_packs = []
|
||||||
|
|
||||||
|
@ -335,13 +291,13 @@ class Gui:
|
||||||
Check if an update is available
|
Check if an update is available
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
github_version_data = requests.get(VERSION_FILE_URL, allow_redirects=True).json()
|
github_version_data = requests.get(VERSION_FILE_URL, allow_redirects=True, timeout=3).json()
|
||||||
with open("./version", "rb") as f: local_version_data = json.load(f)
|
with open("./version", "rb") as f: local_version_data = json.load(f)
|
||||||
|
|
||||||
local_version = StrictVersion(f"{local_version_data['version']}.{local_version_data['subversion']}")
|
local_version = StrictVersion(f"{local_version_data['version']}.{local_version_data['subversion']}")
|
||||||
github_version = StrictVersion(f"{github_version_data['version']}.{github_version_data['subversion']}")
|
github_version = StrictVersion(f"{github_version_data['version']}.{github_version_data['subversion']}")
|
||||||
|
|
||||||
if github_version > local_version: # if github version is newer than local version
|
if github_version > local_version: # if github version is newer than local version
|
||||||
if messagebox.askyesno(
|
if messagebox.askyesno(
|
||||||
self.translate("Update available !"),
|
self.translate("Update available !"),
|
||||||
self.translate("An update is available, do you want to install it ?",
|
self.translate("An update is available, do you want to install it ?",
|
||||||
|
@ -360,8 +316,9 @@ class Gui:
|
||||||
print(self.translate("finished extracting"))
|
print(self.translate("finished extracting"))
|
||||||
|
|
||||||
os.remove("./download.zip")
|
os.remove("./download.zip")
|
||||||
print(self.translate("starting application..."))
|
|
||||||
os.startfile(os.path.realpath("./Updater/Updater.exe"))
|
print(self.translate("starting application..."))
|
||||||
|
os.startfile(os.path.realpath("./Updater/Updater.exe"))
|
||||||
|
|
||||||
elif local_version > github_version:
|
elif local_version > github_version:
|
||||||
self.is_dev_version = True
|
self.is_dev_version = True
|
||||||
|
@ -380,13 +337,18 @@ class Gui:
|
||||||
"""
|
"""
|
||||||
error = traceback.format_exc()
|
error = traceback.format_exc()
|
||||||
with open("./error.log", "a") as f:
|
with open("./error.log", "a") as f:
|
||||||
f.write(f"---\n"
|
f.write(
|
||||||
f"For game version : {self.game.ctconfig.version}\n"
|
f"---\n"
|
||||||
f"./file/ directory : {os.listdir('./file/')}\n"
|
f"For game version : {self.game.ctconfig.version}\n"
|
||||||
f"GAME/files/ information : {self.game.path, self.game.region}\n"
|
f"./file/ directory : {os.listdir('./file/')}\n"
|
||||||
f"{error}\n"
|
f"ctconfig directory : {os.listdir(self.game.ctconfig.pack_path)}\n"
|
||||||
|
f"GAME/files/ information : {self.game.path, self.game.region}\n"
|
||||||
|
f"{error}\n"
|
||||||
)
|
)
|
||||||
messagebox.showerror(self.translate("Error"), self.translate("An error occured", " :", "\n", error, "\n\n"))
|
messagebox.showerror(
|
||||||
|
self.translate("Error"),
|
||||||
|
self.translate("An error occured", " :", "\n", error, "\n\n")
|
||||||
|
)
|
||||||
|
|
||||||
def progress(self, show: bool = None, indeter: bool = None, step: int = None,
|
def progress(self, show: bool = None, indeter: bool = None, step: int = None,
|
||||||
statut: str = None, max: int = None, add: int = None) -> None:
|
statut: str = None, max: int = None, add: int = None) -> None:
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Option:
|
||||||
self.save_to_file()
|
self.save_to_file()
|
||||||
if need_restart: restart()
|
if need_restart: restart()
|
||||||
|
|
||||||
def load_from_file(self, option_file: str = "./option.json") -> None:
|
def load_from_file(self, option_file: str = "./option.json"):
|
||||||
"""
|
"""
|
||||||
Load all options from a json file
|
Load all options from a json file
|
||||||
:param option_file: the file where to load option
|
:param option_file: the file where to load option
|
||||||
|
@ -40,6 +40,8 @@ class Option:
|
||||||
file_json = json.load(file)
|
file_json = json.load(file)
|
||||||
self.load_from_json(file_json)
|
self.load_from_json(file_json)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
def load_from_json(self, option_json: dict) -> None:
|
def load_from_json(self, option_json: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Load all options from a dictionnary
|
Load all options from a dictionnary
|
||||||
|
|
|
@ -5,8 +5,8 @@ from source.wszst import *
|
||||||
HiddenTrackAttr = [
|
HiddenTrackAttr = [
|
||||||
"file_wu8",
|
"file_wu8",
|
||||||
"file_szs",
|
"file_szs",
|
||||||
"track_wu8_dir",
|
"_track_wu8_dir",
|
||||||
"track_szs_dir"
|
"_track_szs_dir"
|
||||||
] # These attribute shouldn't be used to reference all the possibilities of values
|
] # These attribute shouldn't be used to reference all the possibilities of values
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ class Track:
|
||||||
:param since_version: since when version did the track got added to the mod
|
:param since_version: since when version did the track got added to the mod
|
||||||
:param score: what it the score of the track
|
:param score: what it the score of the track
|
||||||
:param warning: what is the warn level of the track (0 = none, 1 = minor bug, 2 = major bug)
|
:param warning: what is the warn level of the track (0 = none, 1 = minor bug, 2 = major bug)
|
||||||
:param note: note about the track
|
|
||||||
:param track_wu8_dir: where is stored the track wu8
|
:param track_wu8_dir: where is stored the track wu8
|
||||||
:param track_szs_dir: where is stored the track szs
|
:param track_szs_dir: where is stored the track szs
|
||||||
:param track_version: version of the track
|
:param track_version: version of the track
|
||||||
|
@ -66,12 +65,11 @@ class Track:
|
||||||
self.since_version = since_version # Since which version is this track available
|
self.since_version = since_version # Since which version is this track available
|
||||||
self.score = score # Track score between 1 and 3 stars
|
self.score = score # Track score between 1 and 3 stars
|
||||||
self.warning = warning # Track bug level (1 = minor, 2 = major)
|
self.warning = warning # Track bug level (1 = minor, 2 = major)
|
||||||
self.note = note # Note about the track
|
|
||||||
self.version = version
|
self.version = version
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
|
|
||||||
self.track_wu8_dir = track_wu8_dir
|
self._track_wu8_dir = track_wu8_dir
|
||||||
self.track_szs_dir = track_szs_dir
|
self._track_szs_dir = track_szs_dir
|
||||||
self.file_wu8 = f"{track_wu8_dir}/{self.sha1}.wu8"
|
self.file_wu8 = f"{track_wu8_dir}/{self.sha1}.wu8"
|
||||||
self.file_szs = f"{track_szs_dir}/{self.sha1}.szs"
|
self.file_szs = f"{track_szs_dir}/{self.sha1}.szs"
|
||||||
|
|
||||||
|
@ -100,7 +98,10 @@ class Track:
|
||||||
"""
|
"""
|
||||||
convert track to szs
|
convert track to szs
|
||||||
"""
|
"""
|
||||||
szs.normalize(src_file=self.file_wu8)
|
szs.normalize(
|
||||||
|
src_file=self.file_wu8,
|
||||||
|
dest_dir="./file/Track/"
|
||||||
|
)
|
||||||
|
|
||||||
def get_author_str(self) -> str:
|
def get_author_str(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -128,7 +129,8 @@ class Track:
|
||||||
else:
|
else:
|
||||||
ctfile_text += (
|
ctfile_text += (
|
||||||
f'"-"; ' # track path, not used in Race_*.szs, save a bit of space
|
f'"-"; ' # track path, not used in Race_*.szs, save a bit of space
|
||||||
f'"{self.get_track_formatted_name(ct_config, *args, **kwargs)}\\n{self.get_author_str()}"; ' # only in race show author's name
|
f'"{self.get_track_formatted_name(ct_config, *args, **kwargs)}\\n{self.get_author_str()}"; '
|
||||||
|
# only in race show author's name
|
||||||
f'"-"\n' # sha1, not used in Race_*.szs, save a bit of space
|
f'"-"\n' # sha1, not used in Race_*.szs, save a bit of space
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -185,8 +187,8 @@ class Track:
|
||||||
for key, value in track_json.items(): # load all value in the json as class attribute
|
for key, value in track_json.items(): # load all value in the json as class attribute
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
self.file_wu8 = f"{self.track_wu8_dir}/{self.sha1}.wu8"
|
self.file_wu8 = f"{self._track_wu8_dir}/{self.sha1}.wu8"
|
||||||
self.file_szs = f"{self.track_szs_dir}/{self.sha1}.szs"
|
self.file_szs = f"{self._track_szs_dir}/{self.sha1}.szs"
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,13 @@ WIMGT_PATH = "./tools/szs/wimgt"
|
||||||
|
|
||||||
|
|
||||||
@error.better_wszst_error(wszst_tools=WIMGT_PATH)
|
@error.better_wszst_error(wszst_tools=WIMGT_PATH)
|
||||||
def encode(file: str, format: str) -> None:
|
def encode(file: str, format: str, dest_file: str = None) -> None:
|
||||||
"""
|
"""
|
||||||
Encode an .png image into a new format
|
Encode an .png image into a new format
|
||||||
|
:param dest_file: destination
|
||||||
:param file: .png image
|
:param file: .png image
|
||||||
:param format: new image format
|
:param format: new image format
|
||||||
"""
|
"""
|
||||||
subprocess.run([WIMGT_PATH, "ENCODE", file, "-x", format, "--overwrite"],
|
cmd = [WIMGT_PATH, "ENCODE", file, "-x", format, "--overwrite"]
|
||||||
creationflags=subprocess.CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE)
|
if dest_file: cmd.extend(["--dest", dest_file])
|
||||||
|
subprocess.run(cmd, creationflags=subprocess.CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE)
|
||||||
|
|
Loading…
Reference in a new issue