diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 6ba0e35e0a3a..4951c6d37bc5 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -1,6 +1,7 @@ import logging +import typing from random import Random -from typing import Dict, Any, Iterable, Optional, Union, List, TextIO +from typing import Dict, Any, Iterable, Optional, Union, List, TextIO, Set from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState from Options import PerGameCommonOptions @@ -10,7 +11,7 @@ from .bundles.bundles import get_all_bundles from .content import content_packs, StardewContent, unpack_content, create_content from .early_items import setup_early_items -from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs +from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs, generate_filler_choice_pool from .locations import location_table, create_locations, LocationData, locations_by_tag from .logic.bundle_logic import BundleLogic from .logic.logic import StardewLogic @@ -20,6 +21,7 @@ from .options.forced_options import force_change_options_if_incompatible from .options.option_groups import sv_option_groups from .options.presets import sv_options_presets +from .options.worlds_group import apply_most_restrictive_options from .regions import create_regions from .rules import set_rules from .stardew_rule import True_, StardewRule, HasProgressionPercent, true_ @@ -96,6 +98,16 @@ class StardewValleyWorld(World): total_progression_items: int excluded_from_total_progression_items: List[str] = [Event.received_walnuts] + @classmethod + def create_group(cls, multiworld: "MultiWorld", new_player_id: int, players: Set[int]) -> World: + world_group = super().create_group(multiworld, new_player_id, players) + + group_options = typing.cast(StardewValleyOptions, world_group.options) + worlds_options = [typing.cast(StardewValleyOptions, multiworld.worlds[player].options) for player in players] + apply_most_restrictive_options(group_options, worlds_options) + + return world_group + def __init__(self, multiworld: MultiWorld, player: int): super().__init__(multiworld, player) self.filler_item_pool_names = [] @@ -326,32 +338,9 @@ def generate_basic(self): def get_filler_item_name(self) -> str: if not self.filler_item_pool_names: - self.generate_filler_item_pool_names() + self.filler_item_pool_names = generate_filler_choice_pool(self.options) return self.random.choice(self.filler_item_pool_names) - def generate_filler_item_pool_names(self): - include_traps, exclude_island = self.get_filler_item_rules() - available_filler = get_all_filler_items(include_traps, exclude_island) - available_filler = remove_limited_amount_packs(available_filler) - self.filler_item_pool_names = [item.name for item in available_filler] - - def get_filler_item_rules(self): - if self.player in self.multiworld.groups: - link_group = self.multiworld.groups[self.player] - include_traps = True - exclude_island = False - for player in link_group["players"]: - player_options = self.multiworld.worlds[player].options - if self.multiworld.game[player] != self.game: - continue - if player_options.trap_items == TrapItems.option_no_traps: - include_traps = False - if player_options.exclude_ginger_island == ExcludeGingerIsland.option_true: - exclude_island = True - return include_traps, exclude_island - else: - return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - def write_spoiler_header(self, spoiler_handle: TextIO) -> None: """Write to the spoiler header. If individual it's right at the end of that player's options, if as stage it's right under the common header before per-player options.""" diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 6ac827f869cc..2eeeaeff5334 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -818,6 +818,16 @@ def remove_excluded_items_island_mods(items, exclude_ginger_island: bool, mods: return mod_filter +def generate_filler_choice_pool(options: StardewValleyOptions) -> list[str]: + include_traps = options.trap_items != TrapItems.option_no_traps + exclude_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true + + available_filler = get_all_filler_items(include_traps, exclude_island) + available_filler = remove_limited_amount_packs(available_filler) + + return available_filler + + def remove_limited_amount_packs(packs): return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.EXACTLY_TWO not in pack.groups] diff --git a/worlds/stardew_valley/options/worlds_group.py b/worlds/stardew_valley/options/worlds_group.py new file mode 100644 index 000000000000..bbf508c61c04 --- /dev/null +++ b/worlds/stardew_valley/options/worlds_group.py @@ -0,0 +1,14 @@ +from typing import Iterable + +from .options import StardewValleyOptions + + +def apply_most_restrictive_options(group_option: StardewValleyOptions, world_options: Iterable[StardewValleyOptions]) -> None: + """Merge the options of the worlds member of the group that can impact fillers generation into the option class of the group. + """ + + # If at least one world disabled ginger island, disabling it for the whole group + group_option.exclude_ginger_island.value = max(o.exclude_ginger_island.value for o in world_options) + + # If at least one world disabled traps, disabling them for the whole group + group_option.trap_items.value = min(o.trap_items.value for o in world_options)