forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
143 lines
5.8 KiB
Python
143 lines
5.8 KiB
Python
import os
|
|
|
|
from .options import TrackmaniaOptions, create_option_groups
|
|
from .items import build_items, trackmania_item_groups, create_itempool, create_item, get_filler_item_name
|
|
from .locations import build_locations
|
|
from .regions import create_regions
|
|
from .rules import set_rules
|
|
from worlds.AutoWorld import World, WebWorld
|
|
from worlds.LauncherComponents import Component, components, icon_paths, launch_subprocess, Type
|
|
from Utils import local_path
|
|
from BaseClasses import Item, Tutorial
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from BaseClasses import MultiWorld
|
|
|
|
def launch_client():
|
|
from .client import launch
|
|
launch_subprocess(launch, name="TrackmaniaClient")
|
|
|
|
icon_path : str = local_path('data', 'tmicon.ico')
|
|
icon: str = 'icon'
|
|
|
|
if os.path.exists(icon_path):
|
|
icon_paths['tmicon'] = icon_path
|
|
icon = 'tmicon'
|
|
|
|
components.append(Component("Trackmania Client", "TrackmaniaClient", func=launch_client,
|
|
component_type=Type.CLIENT, icon=icon))
|
|
|
|
class Webmania(WebWorld):
|
|
theme = "grassFlowers"
|
|
option_groups = create_option_groups()
|
|
tutorials = [Tutorial(
|
|
"Multiworld Setup Guide",
|
|
"A guide for setting up Trackmania to be played in Archipelago.",
|
|
"English",
|
|
"setup_en.md",
|
|
"setup/en",
|
|
["SerialBoxes"]
|
|
)]
|
|
rich_text_options_doc = True
|
|
|
|
class TrackmaniaWorld(World):
|
|
"""Trackmania is a mechanically deep arcade racing game that is easy to pick up and addicting to master!
|
|
Zoom through hundreds of thousands of user-made tracks as fast as you can!"""
|
|
game = "Trackmania" # name of the game/world
|
|
options_dataclass = TrackmaniaOptions # options the player can set
|
|
options: TrackmaniaOptions # typing hints for option results
|
|
web = Webmania()
|
|
|
|
item_name_to_id = build_items()
|
|
location_name_to_id = build_locations()
|
|
|
|
item_name_groups = trackmania_item_groups
|
|
|
|
def __init__(self, multiworld: "MultiWorld", player: int):
|
|
super().__init__(multiworld, player)
|
|
self.series_data: list = []
|
|
|
|
def create_item(self, name: str) -> Item:
|
|
return create_item(self, name)
|
|
|
|
def create_items(self):
|
|
self.multiworld.itempool += create_itempool(self)
|
|
|
|
#rules are also generated with the regions
|
|
def create_regions(self):
|
|
create_regions(self)
|
|
|
|
def set_rules(self):
|
|
set_rules(self)
|
|
|
|
def generate_early(self):
|
|
medal_percent: float = float(self.options.medal_requirement.value) / 100.0
|
|
base_search_criteria: dict = self.options.custom_series.value.get("all", {})
|
|
|
|
if self.options.series_minimum_map_number.value > self.options.series_maximum_map_number.value:
|
|
temp: int = self.options.series_minimum_map_number.value
|
|
self.options.series_minimum_map_number.value = self.options.series_maximum_map_number.value
|
|
self.options.series_maximum_map_number.value = temp
|
|
|
|
if self.options.map_min_length > self.options.map_max_length:
|
|
self.options.map_max_length = self.options.map_min_length+1
|
|
|
|
for series in range(1, self.options.series_number.value + 1):
|
|
map_count: int = self.random.randint(self.options.series_minimum_map_number.value,
|
|
self.options.series_maximum_map_number.value)
|
|
if series == 1 and self.options.first_series_size.value > 0:
|
|
map_count = self.options.first_series_size.value
|
|
|
|
medals: int = round(map_count * medal_percent)
|
|
medals = max(1, min(medals, map_count)) # clamp between 1 and map_count
|
|
|
|
search_criteria: dict = base_search_criteria.copy()
|
|
search_criteria.update(self.options.custom_series.value.get(series, {}))
|
|
|
|
# Fill in global defaults and settings
|
|
if "map_tags" not in search_criteria:
|
|
tags: list = list(self.options.map_tags.value)
|
|
if self.options.random_series_tags > 0 and len(tags) > 1:
|
|
search_criteria["map_tags"] = [self.random.choice(tags)]
|
|
else:
|
|
search_criteria["map_tags"] = tags
|
|
|
|
if "map_etags" not in search_criteria:
|
|
search_criteria["map_etags"] = list(self.options.map_etags.value)
|
|
|
|
if "map_tags_inclusive" not in search_criteria:
|
|
search_criteria["map_tags_inclusive"] = self.options.map_tags_inclusive.value
|
|
|
|
if "difficulties" not in search_criteria:
|
|
search_criteria["difficulties"] = list(self.options.difficulties.value)
|
|
|
|
if "max_length" not in search_criteria:
|
|
search_criteria["max_length"] = self.options.map_max_length * 1000
|
|
|
|
if "min_length" not in search_criteria:
|
|
search_criteria["min_length"] = self.options.map_min_length * 1000
|
|
|
|
if "has_award" not in search_criteria:
|
|
search_criteria["has_award"] = self.options.has_award.value
|
|
|
|
values : dict = {"MedalTotal": medals,
|
|
"MapCount": map_count,
|
|
"SearchCriteria": search_criteria}
|
|
self.series_data.append(values)
|
|
|
|
def fill_slot_data(self) -> dict:
|
|
return {
|
|
"TargetTimeSetting": (float(self.options.target_time.value) / 100.0),
|
|
"DiscountAmount": (float(self.options.discount_amount) / 1000.0),
|
|
"SeriesNumber": self.options.series_number.value,
|
|
"DisableBronze": self.options.disable_bronze_locations.value,
|
|
"DisableSilver": self.options.disable_silver_locations.value,
|
|
"DisableGold": self.options.disable_gold_locations.value,
|
|
"DisableAuthor": self.options.disable_author_locations.value,
|
|
"SeriesData": self.series_data
|
|
}
|
|
|
|
def get_filler_item_name(self) -> str:
|
|
return get_filler_item_name(self)
|