started restructuring pack (part 3), added ct_icons generation, added ExtractedGame class alongside Game, started install_all_patch function
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -44,7 +44,7 @@
|
||||||
"SK64": "green",
|
"SK64": "green",
|
||||||
"SMG": "red2",
|
"SMG": "red2",
|
||||||
"Spyro 1": "blue",
|
"Spyro 1": "blue",
|
||||||
"Wii U": "red4",
|
"Switch": "red4",
|
||||||
"Wii": "blue",
|
"Wii": "blue",
|
||||||
"3DS": "YOR3",
|
"3DS": "YOR3",
|
||||||
"DS": "white",
|
"DS": "white",
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
"tags_suffix": {
|
"tags_suffix": {
|
||||||
"Boost": "orange"
|
"Boost": "orange"
|
||||||
},
|
},
|
||||||
"tags_cups": ["Wii U", "3DS", "DS", "GCN", "GBA", "N64", "SNES", "MKT", "RMX", "DX", "GP"],
|
"tags_cups": ["Switch", "3DS", "DS", "GCN", "GBA", "N64", "SNES", "MKT", "RMX", "DX", "GP"],
|
||||||
|
|
||||||
"track_formatting": {
|
"track_formatting": {
|
||||||
"menu_name": "{{ ('\\c{YOR2}\\x'+hex(65296+getattr(track, 'score'))[2:]+'\\{off} ') if hasattr(track, 'score') else '' }}{{ (prefix+' ') if prefix else '' }}{{ getattr(track, 'name', '') }}{{ (' ('+suffix +')') if suffix else '' }}",
|
"menu_name": "{{ ('\\c{YOR2}\\x'+hex(65296+getattr(track, 'score'))[2:]+'\\{off} ') if hasattr(track, 'score') else '' }}{{ (prefix+' ') if prefix else '' }}{{ getattr(track, 'name', '') }}{{ (' ('+suffix +')') if suffix else '' }}",
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
"score":3,
|
"score":3,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
"version":"RC1",
|
"version":"RC1",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
"version":"v1.2b",
|
"version":"v1.2b",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
"version":"v1",
|
"version":"v1",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
"version":"RC1",
|
"version":"RC1",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -162,7 +162,7 @@
|
||||||
"score":4,
|
"score":4,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@
|
||||||
"score":3,
|
"score":3,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
],
|
],
|
||||||
"note":"some collision (like the plane) are buggy, and the texture feel a bit too dark"
|
"note":"some collision (like the plane) are buggy, and the texture feel a bit too dark"
|
||||||
},
|
},
|
||||||
|
@ -191,7 +191,7 @@
|
||||||
"version":"v1.1",
|
"version":"v1.1",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -205,7 +205,7 @@
|
||||||
"score":5,
|
"score":5,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
"score":5,
|
"score":5,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -233,7 +233,7 @@
|
||||||
"score":5,
|
"score":5,
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
"since_version":"0.1",
|
"since_version":"0.1",
|
||||||
"tags":[
|
"tags":[
|
||||||
"Retro",
|
"Retro",
|
||||||
"Wii U"
|
"Switch"
|
||||||
],
|
],
|
||||||
"sha1":"e782de12471731e9bb155eea6872cd5b2303357d",
|
"sha1":"e782de12471731e9bb155eea6872cd5b2303357d",
|
||||||
"version":"v1.3"
|
"version":"v1.3"
|
||||||
|
|
|
@ -1,32 +1,64 @@
|
||||||
# class that represent a mario kart wii cup
|
# class that represent a mario kart wii cup
|
||||||
from PIL import Image
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
|
||||||
class Cup:
|
class Cup:
|
||||||
__slots__ = ["_tracks", "cup_id"]
|
__slots__ = ["_tracks", "cup_name", "cup_id"]
|
||||||
_last_cup_id = 0
|
_last_cup_id = 0
|
||||||
|
|
||||||
def __init__(self, tracks: list["Track | TrackGroup"], cup_id: str | None = None):
|
def __init__(self, tracks: list["Track | TrackGroup"], cup_name: str | None = None):
|
||||||
self._tracks = tracks[:4]
|
self._tracks = tracks[:4]
|
||||||
|
|
||||||
if cup_id is None:
|
self.cup_id = self.__class__._last_cup_id
|
||||||
cup_id = self.__class__._last_cup_id
|
self.cup_name = cup_name if cup_name is not None else self.cup_id
|
||||||
self.__class__._last_cup_id += 1
|
self.__class__._last_cup_id += 1
|
||||||
|
|
||||||
self.cup_id = cup_id
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Cup id={self.cup_id} tracks={self._tracks}>"
|
return f"<Cup name={self.cup_name} id={self.cup_id} tracks={self._tracks}>"
|
||||||
|
|
||||||
def get_cup_icon(self) -> Image.Image:
|
def get_default_cticon(self, mod_config: "ModConfig") -> Image.Image:
|
||||||
...
|
"""
|
||||||
|
Get the default cticon for this cup
|
||||||
|
:return: the default cticon
|
||||||
|
"""
|
||||||
|
ct_icon = Image.new("RGBA", (128, 128))
|
||||||
|
draw = ImageDraw.Draw(ct_icon)
|
||||||
|
|
||||||
|
draw.text(
|
||||||
|
(4, 4),
|
||||||
|
"CT",
|
||||||
|
(255, 165, 0),
|
||||||
|
font=ImageFont.truetype(mod_config.get_default_font(), 90),
|
||||||
|
stroke_width=2,
|
||||||
|
stroke_fill=(0, 0, 0)
|
||||||
|
)
|
||||||
|
draw.text(
|
||||||
|
(5, 80),
|
||||||
|
f"{self.cup_id:03}",
|
||||||
|
(255, 165, 0),
|
||||||
|
font=ImageFont.truetype(mod_config.get_default_font(), 60),
|
||||||
|
stroke_width=2,
|
||||||
|
stroke_fill=(0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
return ct_icon
|
||||||
|
|
||||||
|
def get_cticon(self, mod_config: "ModConfig") -> Image.Image:
|
||||||
|
"""
|
||||||
|
Get the cticon for this cup
|
||||||
|
:return: the cticon
|
||||||
|
"""
|
||||||
|
path = mod_config.get_mod_directory() / f"_CUPS/{self.cup_name}.png"
|
||||||
|
if path.exists(): return Image.open(path)
|
||||||
|
# if the icon doesn't exist, use the default automatically generated one
|
||||||
|
return self.get_default_cticon(mod_config=mod_config)
|
||||||
|
|
||||||
def get_ctfile(self, mod_config: "ModConfig") -> str:
|
def get_ctfile(self, mod_config: "ModConfig") -> str:
|
||||||
"""
|
"""
|
||||||
Get the ctfile for this cup
|
Get the ctfile for this cup
|
||||||
:return: the ctfile
|
:return: the ctfile
|
||||||
"""
|
"""
|
||||||
ctfile = f'C "{self.cup_id}"\n'
|
ctfile = f'C "{self.cup_name}"\n'
|
||||||
for track in self._tracks: ctfile += track.get_ctfile(mod_config=mod_config)
|
for track in self._tracks: ctfile += track.get_ctfile(mod_config=mod_config)
|
||||||
ctfile += "\n"
|
ctfile += "\n"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
|
@ -6,25 +7,69 @@ from source.wt import szs
|
||||||
from source.wt.wit import WITPath, Region, Extension
|
from source.wt.wit import WITPath, Region, Extension
|
||||||
|
|
||||||
|
|
||||||
def extract_autoadd(extracted_game: Path | str, destination_path: Path | str) -> Path:
|
class ExtractedGame:
|
||||||
"""
|
"""
|
||||||
Extract all the autoadd files from the game to destination_path
|
Class that represents an extracted game
|
||||||
:param extracted_game: path of the extracted game
|
|
||||||
:param destination_path: directory where the autoadd files will be extracted
|
|
||||||
:return: directory where the autoadd files were extracted
|
|
||||||
"""
|
"""
|
||||||
yield {"description": "Extracting autoadd files...", "determinate": False}
|
def __init__(self, path: Path | str):
|
||||||
szs.autoadd(extracted_game / "files/Race/Course/", destination_path)
|
self.path = Path(path)
|
||||||
|
|
||||||
|
def extract_autoadd(self, destination_path: Path | str) -> Generator[dict, None, None]:
|
||||||
|
"""
|
||||||
|
Extract all the autoadd files from the game to destination_path
|
||||||
|
:param destination_path: directory where the autoadd files will be extracted
|
||||||
|
:return: directory where the autoadd files were extracted
|
||||||
|
"""
|
||||||
|
yield {"description": "Extracting autoadd files...", "determinate": False}
|
||||||
|
szs.autoadd(self.path / "files/Race/Course/", destination_path)
|
||||||
|
|
||||||
def install_mystuff(extracted_game: Path | str) -> None:
|
def install_mystuff(self) -> Generator[dict, None, None]:
|
||||||
"""
|
"""
|
||||||
Install mystuff directory
|
Install mystuff directory
|
||||||
:param extracted_game: the extracted game
|
:return:
|
||||||
:return:
|
"""
|
||||||
"""
|
yield {"description": "Installing MyStuff directory...", "determinate": False}
|
||||||
yield {"description": "Installing MyStuff directory...", "determinate": False}
|
...
|
||||||
|
|
||||||
|
def install_file(self, mod_config: ModConfig, patch_directory: Path | str, subfile: Path | str) \
|
||||||
|
-> Generator[dict, None, None]:
|
||||||
|
"""
|
||||||
|
Install a file into the game
|
||||||
|
:param patch_directory: patch_directory where the subfile is located
|
||||||
|
:param subfile: subfile to install
|
||||||
|
:param mod_config: the mod to install
|
||||||
|
"""
|
||||||
|
subfile = Path(subfile)
|
||||||
|
yield {"description": f"Installing {subfile.name}...", "determinate": False}
|
||||||
|
|
||||||
|
configuration = {}
|
||||||
|
configuration_path = subfile.with_suffix(subfile.suffix + ".json")
|
||||||
|
if configuration_path.exists(): configuration |= json.loads(configuration_path.read_text(encoding="utf8"))
|
||||||
|
|
||||||
|
def install_patch(self, mod_config: ModConfig, patch_directory: Path | str) -> Generator[dict, None, None]:
|
||||||
|
"""
|
||||||
|
Install a patch into the game
|
||||||
|
:param mod_config: the mod to install
|
||||||
|
:param patch_directory: directory containing the patch
|
||||||
|
"""
|
||||||
|
patch_directory = Path(patch_directory)
|
||||||
|
yield {"description": f"Installing Patch {patch_directory.parent.name}...", "determinate": False}
|
||||||
|
|
||||||
|
for subfile in filter(lambda sf: sf.suffix == ".json", patch_directory.rglob("*")):
|
||||||
|
self.install_file(mod_config, subfile)
|
||||||
|
|
||||||
|
def install_all_patch(self, mod_config: ModConfig) -> Generator[dict, None, None]:
|
||||||
|
"""
|
||||||
|
Install all patchs of the mod_config into the game
|
||||||
|
:param mod_config: the mod to install
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
yield {"description": "Installing all Patch...", "determinate": False}
|
||||||
|
|
||||||
|
# for all directory that are in the root of the mod, and don't start with an underscore,
|
||||||
|
# for all of the subdirectory named "_PATCH", apply the patch
|
||||||
|
for patch_directory in mod_config.get_mod_directory().glob("[!_]*").rglob("_PATCH/"):
|
||||||
|
self.install_patch(mod_config, patch_directory)
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
|
@ -63,9 +108,11 @@ class Game:
|
||||||
except StopIteration as e:
|
except StopIteration as e:
|
||||||
return e.value
|
return e.value
|
||||||
|
|
||||||
def get_output_directory(self, dest: Path | str, mod_config: ModConfig) -> Path:
|
@staticmethod
|
||||||
|
def get_output_directory(dest: Path | str, mod_config: ModConfig) -> Path:
|
||||||
"""
|
"""
|
||||||
Return the directory where the game will be installed
|
Return the directory where the game will be installed
|
||||||
|
:param dest: destination directory
|
||||||
:param mod_config: mod configuration
|
:param mod_config: mod configuration
|
||||||
:return: directory where the game will be installed
|
:return: directory where the game will be installed
|
||||||
"""
|
"""
|
||||||
|
@ -94,9 +141,10 @@ class Game:
|
||||||
cache_directory.mkdir(parents=True, exist_ok=True)
|
cache_directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# get the directory where the game will be extracted
|
# get the directory where the game will be extracted
|
||||||
extracted_game: Path = self.get_output_directory(dest, mod_config)
|
extracted_game = ExtractedGame(self.get_output_directory(dest, mod_config))
|
||||||
|
|
||||||
yield from self.extract(extracted_game)
|
yield from self.extract(extracted_game.path)
|
||||||
yield from extract_autoadd(extracted_game, cache_directory / "autoadd/")
|
yield from extracted_game.extract_autoadd(cache_directory / "autoadd/")
|
||||||
yield from install_mystuff(extracted_game)
|
yield from extracted_game.install_mystuff()
|
||||||
|
yield from extracted_game.install_all_patch(mod_config)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
from source.mkw import Tag, Color
|
from source.mkw import Tag, Color
|
||||||
from source.mkw.Cup import Cup
|
from source.mkw.Cup import Cup
|
||||||
from source.mkw.Track import Track
|
from source.mkw.Track import Track
|
||||||
|
@ -9,11 +11,11 @@ import json
|
||||||
|
|
||||||
# representation of the configuration of a mod
|
# representation of the configuration of a mod
|
||||||
class ModConfig:
|
class ModConfig:
|
||||||
__slots__ = ("name", "nickname", "variant", "region", "tags_prefix", "tags_suffix",
|
__slots__ = ("name", "path", "nickname", "variant", "region", "tags_prefix", "tags_suffix",
|
||||||
"default_track", "_tracks", "version", "original_track_prefix", "swap_original_order",
|
"default_track", "_tracks", "version", "original_track_prefix", "swap_original_order",
|
||||||
"keep_original_track", "enable_random_cup", "tags_cups", "track_formatting")
|
"keep_original_track", "enable_random_cup", "tags_cups", "track_formatting")
|
||||||
|
|
||||||
def __init__(self, name: str, nickname: str = None, version: str = None, variant: str = None,
|
def __init__(self, path: Path | str, name: str, nickname: str = None, version: str = None, variant: str = None,
|
||||||
tags_prefix: dict[Tag, Color] = None, tags_suffix: dict[Tag, Color] = None,
|
tags_prefix: dict[Tag, Color] = None, tags_suffix: dict[Tag, Color] = None,
|
||||||
tags_cups: list[Tag] = None, region: dict[int] | int = None,
|
tags_cups: list[Tag] = None, region: dict[int] | int = None,
|
||||||
default_track: "Track | TrackGroup" = None, tracks: list["Track | TrackGroup"] = None,
|
default_track: "Track | TrackGroup" = None, tracks: list["Track | TrackGroup"] = None,
|
||||||
|
@ -21,6 +23,8 @@ class ModConfig:
|
||||||
keep_original_track: bool = None, enable_random_cup: bool = None,
|
keep_original_track: bool = None, enable_random_cup: bool = None,
|
||||||
track_formatting: dict[str, str] = None):
|
track_formatting: dict[str, str] = None):
|
||||||
|
|
||||||
|
self.path = Path(path)
|
||||||
|
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
self.nickname: str = nickname if nickname is not None else name
|
self.nickname: str = nickname if nickname is not None else name
|
||||||
self.version: str = version if version is not None else "v1.0.0"
|
self.version: str = version if version is not None else "v1.0.0"
|
||||||
|
@ -48,20 +52,22 @@ class ModConfig:
|
||||||
return f"<ModConfig name={self.name} version={self.version}>"
|
return f"<ModConfig name={self.name} version={self.version}>"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, config_dict: dict) -> "ModConfig":
|
def from_dict(cls, path: Path | str, config_dict: dict) -> "ModConfig":
|
||||||
"""
|
"""
|
||||||
Create a ModConfig from a dict
|
Create a ModConfig from a dict
|
||||||
|
:param path: path of the mod_config.json
|
||||||
:param config_dict: dict containing the configuration
|
:param config_dict: dict containing the configuration
|
||||||
:return: ModConfig
|
:return: ModConfig
|
||||||
"""
|
"""
|
||||||
kwargs = {
|
kwargs = {
|
||||||
attr: config_dict.get(attr)
|
attr: config_dict.get(attr)
|
||||||
for attr in cls.__slots__
|
for attr in cls.__slots__
|
||||||
if attr not in ["name", "default_track", "_tracks", "tracks"]
|
if attr not in ["name", "default_track", "_tracks", "tracks", "path"]
|
||||||
# these keys are treated after or are reserved
|
# these keys are treated after or are reserved
|
||||||
}
|
}
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
|
path=Path(path),
|
||||||
name=config_dict["name"],
|
name=config_dict["name"],
|
||||||
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
@ -77,8 +83,18 @@ class ModConfig:
|
||||||
:param config_file: file containing the configuration
|
:param config_file: file containing the configuration
|
||||||
:return: ModConfig
|
:return: ModConfig
|
||||||
"""
|
"""
|
||||||
if isinstance(config_file, str): config_file = Path(config_file)
|
config_file = Path(config_file)
|
||||||
return cls.from_dict(json.loads(config_file.read_text(encoding="utf8")))
|
return cls.from_dict(
|
||||||
|
path=config_file,
|
||||||
|
config_dict=json.loads(config_file.read_text(encoding="utf8"))
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_mod_directory(self) -> Path:
|
||||||
|
"""
|
||||||
|
Get the directory of the mod
|
||||||
|
:return: directory of the mod
|
||||||
|
"""
|
||||||
|
return self.path.parent
|
||||||
|
|
||||||
def get_tracks(self) -> Generator["Track", None, None]:
|
def get_tracks(self) -> Generator["Track", None, None]:
|
||||||
"""
|
"""
|
||||||
|
@ -105,13 +121,13 @@ class ModConfig:
|
||||||
|
|
||||||
if len(track_buffer) > 4:
|
if len(track_buffer) > 4:
|
||||||
current_tag_count += 1
|
current_tag_count += 1
|
||||||
yield Cup(tracks=track_buffer, cup_id=f"{current_tag_name}-{current_tag_count}")
|
yield Cup(tracks=track_buffer, cup_name=f"{current_tag_name}/{current_tag_count}")
|
||||||
track_buffer = []
|
track_buffer = []
|
||||||
|
|
||||||
# if there is still tracks in the buffer, create a cup with them and fill with default>
|
# if there is still tracks in the buffer, create a cup with them and fill with default>
|
||||||
if len(track_buffer) > 0:
|
if len(track_buffer) > 0:
|
||||||
track_buffer.extend([self.default_track] * (4 - len(track_buffer)))
|
track_buffer.extend([self.default_track] * (4 - len(track_buffer)))
|
||||||
yield Cup(tracks=track_buffer, cup_id=f"{current_tag_name}-{current_tag_count+1}")
|
yield Cup(tracks=track_buffer, cup_name=f"{current_tag_name}/{current_tag_count+1}")
|
||||||
|
|
||||||
def get_unordered_cups(self) -> Generator["Cup", None, None]:
|
def get_unordered_cups(self) -> Generator["Cup", None, None]:
|
||||||
"""
|
"""
|
||||||
|
@ -167,3 +183,61 @@ class ModConfig:
|
||||||
ctfile += cup.get_ctfile(mod_config=self)
|
ctfile += cup.get_ctfile(mod_config=self)
|
||||||
|
|
||||||
return ctfile
|
return ctfile
|
||||||
|
|
||||||
|
def get_base_cticons(self) -> Generator[Image.Image, None, None]:
|
||||||
|
"""
|
||||||
|
Return the base cticon
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
icon_names = ["left", "right"]
|
||||||
|
|
||||||
|
if self.keep_original_track:
|
||||||
|
icon_names += [
|
||||||
|
f"_DEFAULT/{name}"
|
||||||
|
for name in (
|
||||||
|
["mushroom", "shell", "flower", "banana", "star", "leaf", "special", "lightning"]
|
||||||
|
if self.swap_original_order else
|
||||||
|
["mushroom", "flower", "star", "special", "shell", "banana", "leaf", "lightning"]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
if self.enable_random_cup: icon_names.append("random")
|
||||||
|
|
||||||
|
for icon_name in icon_names:
|
||||||
|
yield Image.open(self.get_mod_directory() / f"{icon_name}.png").resize((128, 128))
|
||||||
|
|
||||||
|
def get_custom_cticons(self) -> Generator[Image.Image, None, None]:
|
||||||
|
"""
|
||||||
|
Return the custom ct_icon generated from the ModConfig
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for cup in self.get_cups():
|
||||||
|
yield cup.get_cticon(mod_config=self).resize((128, 128))
|
||||||
|
|
||||||
|
def get_cticons(self) -> Generator[Image.Image, None, None]:
|
||||||
|
"""
|
||||||
|
Return all the ct_icon generated from the ModConfig
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
yield from self.get_base_cticons()
|
||||||
|
yield from self.get_custom_cticons()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_default_font() -> Path:
|
||||||
|
"""
|
||||||
|
Return the default font for creating ct_icons
|
||||||
|
:return: the path to the default font file
|
||||||
|
"""
|
||||||
|
# TODO: make it customizable
|
||||||
|
return Path("./assets/SuperMario256.ttf")
|
||||||
|
|
||||||
|
def get_full_cticon(self) -> Image.Image:
|
||||||
|
"""
|
||||||
|
Return the full ct_icon generated from the ModConfig
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
cticons = list(self.get_cticons())
|
||||||
|
|
||||||
|
full_cticon = Image.new("RGBA", (128 * len(cticons), 128))
|
||||||
|
for i, cticon in enumerate(cticons): full_cticon.paste(cticon, (i * 128, 0))
|
||||||
|
|
||||||
|
return full_cticon
|
||||||
|
|