Files
Grinch-AP/worlds/mlss/__init__.py
jamesbrq 5935093615 Mario & Luigi: Superstar Saga: Implement New Game (#2754)
* Commit for PR

* Commit for PR

* Update worlds/mlss/Client.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/docs/setup_en.md

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Remove deprecated import. Updated settings and romfile syntax

* Updated Options to new system. Changed all references from MultiWorld to World

* Changed switch statements to if else

* Update en_Mario & Luigi Superstar Saga.md

* Updated client.py

* Update Client.py

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Updated logic, Updated patch implementation, Removed unused imports, Cleaned up Code

* Update __init__.py

* Changed reference from world to mlssworld

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix merge conflict + update prep

* v1.2

* Leftover print commands

* Update basepatch.bsdiff

* Update basepatch.bsdiff

* v1.3

* Update Rom.py

* Change tracker locations to serverside, no longer locations. Various code cleanup and logic changes.

* Event removal continuation.

* Partial Implementation of APPP (Incomplete))

* v1.4 Implemented APPP

* Docs Updated

* Update Rom.py

* Update setup_en.md

* Update Rom.py

* Update Rules.py

* Fix for APPP being broken on webhost

* Update Rom.py

* Update Rom.py

* Location name fixes + pants color fixes

* Update Rules.py

* Fix for ultra hammer cutscene

* Fixed compat. issues with python ver. 3.8

* Updated hidden block yaml option

* pre-v1.5

* Update Client.py

* Update basepatch.bsdiff

* v1.5

* Update XP multiplier to have a minimum of 0

* Update 'Beanfruit' to 'Bean Fruit'

* v1.6

* Update Rom.py

* Update basepatch.bsdiff

* Initial review refactor

* Revert state logic changes. Continuation of refactor.

* Fixed failed generations. Finished refactor.

* Reworked colors. Removed all .txt files

* Actually removed the .txt files this time

* Update Rom.py

* Update README.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Client.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Data.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Review refactor.

* Update README.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Add coin blocks to LocationName

* Refactor.

* Update Items.py

* Delete mlss.apworld

* Small asm bugfix

* Update basepatch.bsdiff

* Client sends less messages to server

* Update basepatch.bsdiff

---------

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-05-06 09:15:06 +02:00

184 lines
7.8 KiB
Python

import os
import pkgutil
import typing
import settings
from BaseClasses import Tutorial, ItemClassification
from worlds.AutoWorld import WebWorld, World
from typing import List, Dict, Any
from .Locations import all_locations, location_table, bowsers, bowsersMini, hidden, coins
from .Options import MLSSOptions
from .Items import MLSSItem, itemList, item_frequencies, item_table
from .Names.LocationName import LocationName
from .Client import MLSSClient
from .Regions import create_regions, connect_regions
from .Rom import MLSSProcedurePatch, write_tokens
from .Rules import set_rules
class MLSSWebWorld(WebWorld):
theme = "partyTime"
bug_report_page = "https://github.com/jamesbrq/ArchipelagoMLSS/issues"
tutorials = [
Tutorial(
tutorial_name="Setup Guide",
description="A guide to setting up Mario & Luigi: Superstar Saga for Archipelago.",
language="English",
file_name="setup_en.md",
link="setup/en",
authors=["jamesbrq"],
)
]
class MLSSSettings(settings.Group):
class RomFile(settings.UserFilePath):
"""File name of the MLSS US rom"""
copy_to = "Mario & Luigi - Superstar Saga (U).gba"
description = "MLSS ROM File"
md5s = ["4b1a5897d89d9e74ec7f630eefdfd435"]
rom_file: RomFile = RomFile(RomFile.copy_to)
rom_start: bool = True
class MLSSWorld(World):
"""
Adventure with Mario and Luigi together in the Beanbean Kingdom
to stop the evil Cackletta and retrieve the Beanstar.
"""
game = "Mario & Luigi Superstar Saga"
web = MLSSWebWorld()
options_dataclass = MLSSOptions
options: MLSSOptions
settings: typing.ClassVar[MLSSSettings]
item_name_to_id = {name: data.code for name, data in item_table.items()}
location_name_to_id = {loc_data.name: loc_data.id for loc_data in all_locations}
required_client_version = (0, 4, 5)
disabled_locations: List[str]
def generate_early(self) -> None:
self.disabled_locations = []
if self.options.chuckle_beans == 0:
self.disabled_locations += [location.name for location in all_locations if "Digspot" in location.name]
if self.options.castle_skip:
self.disabled_locations += [location.name for location in all_locations if "Bowser" in location.name]
if self.options.chuckle_beans == 1:
self.disabled_locations = [location.name for location in all_locations if location.id in hidden]
if self.options.skip_minecart:
self.disabled_locations += [LocationName.HoohooMountainBaseMinecartCaveDigspot]
if self.options.disable_surf:
self.disabled_locations += [LocationName.SurfMinigame]
if self.options.harhalls_pants:
self.disabled_locations += [LocationName.HarhallsPants]
if not self.options.coins:
self.disabled_locations += [location.name for location in all_locations if location in coins]
def create_regions(self) -> None:
create_regions(self, self.disabled_locations)
connect_regions(self)
item = self.create_item("Mushroom")
self.get_location(LocationName.ShopStartingFlag1).place_locked_item(item)
item = self.create_item("Syrup")
self.get_location(LocationName.ShopStartingFlag2).place_locked_item(item)
item = self.create_item("1-UP Mushroom")
self.get_location(LocationName.ShopStartingFlag3).place_locked_item(item)
item = self.create_item("Hoo Bean")
self.get_location(LocationName.PantsShopStartingFlag1).place_locked_item(item)
item = self.create_item("Chuckle Bean")
self.get_location(LocationName.PantsShopStartingFlag2).place_locked_item(item)
def fill_slot_data(self) -> Dict[str, Any]:
return {
"CastleSkip": self.options.castle_skip.value,
"SkipMinecart": self.options.skip_minecart.value,
"DisableSurf": self.options.disable_surf.value,
"HarhallsPants": self.options.harhalls_pants.value,
"ChuckleBeans": self.options.chuckle_beans.value,
"DifficultLogic": self.options.difficult_logic.value,
"Coins": self.options.coins.value,
}
def create_items(self) -> None:
# First add in all progression and useful items
required_items = []
precollected = [item for item in itemList if item in self.multiworld.precollected_items]
for item in itemList:
if item.classification != ItemClassification.filler and item.classification != ItemClassification.skip_balancing:
freq = item_frequencies.get(item.itemName, 1)
if item in precollected:
freq = max(freq - precollected.count(item), 0)
if self.options.harhalls_pants and "Harhall's" in item.itemName:
continue
required_items += [item.itemName for _ in range(freq)]
for itemName in required_items:
self.multiworld.itempool.append(self.create_item(itemName))
# Then, create our list of filler items
filler_items = []
for item in itemList:
if item.classification != ItemClassification.filler:
continue
if item.itemName == "5 Coins" and not self.options.coins:
continue
freq = item_frequencies.get(item.itemName, 1)
if self.options.chuckle_beans == 0:
if item.itemName == "Chuckle Bean":
continue
if self.options.chuckle_beans == 1:
if item.itemName == "Chuckle Bean":
freq -= 59
filler_items += [item.itemName for _ in range(freq)]
# And finally take as many fillers as we need to have the same amount of items and locations.
remaining = len(all_locations) - len(required_items) - 5
if self.options.castle_skip:
remaining -= len(bowsers) + len(bowsersMini) - (5 if self.options.chuckle_beans == 0 else 0)
if self.options.skip_minecart and self.options.chuckle_beans == 2:
remaining -= 1
if self.options.disable_surf:
remaining -= 1
if self.options.harhalls_pants:
remaining -= 1
if self.options.chuckle_beans == 0:
remaining -= 192
if self.options.chuckle_beans == 1:
remaining -= 59
if not self.options.coins:
remaining -= len(coins)
self.multiworld.itempool += [
self.create_item(filler_item_name) for filler_item_name in self.random.sample(filler_items, remaining)
]
def set_rules(self) -> None:
set_rules(self, self.disabled_locations)
if self.options.castle_skip:
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach(
"PostJokes", "Region", self.player
)
else:
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach(
"Bowser's Castle Mini", "Region", self.player
)
def create_item(self, name: str) -> MLSSItem:
item = item_table[name]
return MLSSItem(item.itemName, item.classification, item.code, self.player)
def get_filler_item_name(self) -> str:
return self.random.choice(list(filter(lambda item: item.classification == ItemClassification.filler, itemList)))
def generate_output(self, output_directory: str) -> None:
patch = MLSSProcedurePatch(player=self.player, player_name=self.multiworld.player_name[self.player])
patch.write_file("base_patch.bsdiff4", pkgutil.get_data(__name__, "data/basepatch.bsdiff"))
write_tokens(self, patch)
rom_path = os.path.join(
output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}" f"{patch.patch_file_ending}"
)
patch.write(rom_path)