""" Archipelago init file for Super Mario Sunshine """ import random, math from dataclasses import fields from typing import Dict, Any import os import settings from BaseClasses import ItemClassification, Tutorial from worlds.AutoWorld import WebWorld, World from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components, launch_subprocess from .items import ALL_ITEMS_TABLE, REGULAR_PROGRESSION_ITEMS, ALL_PROGRESSION_ITEMS, TICKET_ITEMS, JUNK_ITEMS, SmsItem from .locations import ALL_LOCATIONS_TABLE from .options import SmsOptions from .regions import create_regions from .iso_helper.sms_rom import SMSPlayerContainer def run_client(): from .SMSClient import main launch_subprocess(main) components.append( Component("Super Mario Sunshine Client", func=run_client, component_type=Type.CLIENT, file_identifier=SuffixIdentifier(".apsms"))) class SuperMarioSunshineSettings(settings.Group): class ISOFile(settings.UserFilePath): description = "Super Mario Sunshine (USA) NTSC-U ISO File" copy_to = None iso_file: ISOFile = ISOFile(ISOFile.copy_to) class SmsWebWorld(WebWorld): theme = "ocean" tutorials = [Tutorial( "Multiworld Setup Guide", "A guide to playing Super Mario Sunshine. This guide covers single-player, multiworld and related" " software.", "English", "setup_en.md", "setup/en", ["Black Sliver"] )] class SmsWorld(World): """ Tohrik made a mess and now he has to clean it up. Or maybe he didn't. Doesn't matter, CLEAN IT. """ game = "Super Mario Sunshine" web = SmsWebWorld() data_version = 1 options_dataclass = SmsOptions options: SmsOptions item_name_to_id = ALL_ITEMS_TABLE location_name_to_id = ALL_LOCATIONS_TABLE settings: SuperMarioSunshineSettings corona_goal = 50 possible_shines = 0 def generate_early(self): if self.options.starting_nozzle.value == 0: self.options.start_inventory.value["Spray Nozzle"] = 1 elif self.options.starting_nozzle.value == 1: self.options.start_inventory.value["Hover Nozzle"] = 1 if self.options.level_access.value == 1: pick = random.choice(list(TICKET_ITEMS.keys())) tick = str(pick) print(tick) self.options.start_inventory.value[tick] = 1 def create_regions(self): create_regions(self) def create_items(self): pool = [self.create_item(name) for name in REGULAR_PROGRESSION_ITEMS.keys()] if self.options.level_access == 1: pool += [self.create_item(name) for name in TICKET_ITEMS.keys()] if self.options.blue_coin_sanity == "full_shuffle": for _ in range(0, self.options.blue_coin_maximum): pool.append((self.create_item("Blue Coin"))) # Adds the minimum amount required of shines for Corona Mountain access for _ in range(0, self.options.corona_mountain_shines): pool.append(self.create_item("Shine Sprite")) self.possible_shines += 1 extra_shines = math.floor(self.options.corona_mountain_shines * 0.30) # Adds extra shines to the pool if possible if (len(self.multiworld.get_unfilled_locations(self.player))) > 0: for _ in range(0, min(len(self.multiworld.get_unfilled_locations(self.player)), extra_shines)): pool.append(self.create_item("Shine Sprite")) self.possible_shines += 1 if (len(self.multiworld.get_unfilled_locations(self.player))) > 0: for _ in range(0, len(self.multiworld.get_unfilled_locations(self.player))): pool.append(self.create_item(self.random.choice(list(JUNK_ITEMS.keys())))) self.multiworld.itempool += pool def create_item(self, name: str): if name in ALL_PROGRESSION_ITEMS: classification = ItemClassification.progression else: classification = ItemClassification.filler return SmsItem(name, classification, ALL_ITEMS_TABLE[name], self.player) def set_rules(self): self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player) self.corona_goal = min(self.options.corona_mountain_shines.value, self.possible_shines) def fill_slot_data(self) -> Dict[str, Any]: return { "corona_mountain_shines": self.options.corona_mountain_shines.value, "blue_coin_sanity": self.options.blue_coin_sanity.value, "starting_nozzle": self.options.starting_nozzle.value, "ticket_mode": self.options.level_access.value, "boathouse_maximum": self.options.trade_shine_maximum.value, "coin_shine_enabled": self.options.enable_coin_shines.value, "death_link": self.options.death_link.value, "seed": self.multiworld.seed } def generate_output(self, output_directory: str): output_data = { "Seed": self.multiworld.seed, "Slot": self.player, "Name": self.player_name, "Options": {}, "0.6.5": "0.5.1" } for field in fields(self.options): output_data["Options"][field.name] = getattr(self.options, field.name).value patch_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}" f"{SMSPlayerContainer.patch_file_ending}") sms_container = SMSPlayerContainer(output_data, patch_path, self.multiworld.player_name[self.player], self.player) sms_container.write() # def launch_client(): # from .SMSClient import main # launch_subprocess(main, name="SMS client") # def add_client_to_launcher() -> None: # version = "0.2.0" # found = False # for c in components: # if c.display_name == "Super Mario Sunshine Client": # found = True # if getattr(c, "version", 0) < version: # c.version = version # c.func = launch_client # return # if not found: # components.append(Component("Super Mario Sunshine Client", "SMSClient", # func=launch_client)) # add_client_to_launcher()