Stardew Valley: Move filler pool generation out of the world class (#4372)

* merge group options so specific handling is not needed when generating filler pool

* fix

* remove unneeded imports

* self review

* remove unneeded imports

* looks like typing was missing woopsi
This commit is contained in:
Jérémie Bolduc
2025-03-08 12:13:33 -05:00
committed by GitHub
parent ce34b60712
commit 4ebabc1208
5 changed files with 43 additions and 30 deletions

View File

@@ -1,4 +1,5 @@
import logging import logging
import typing
from random import Random from random import Random
from typing import Dict, Any, Iterable, Optional, List, TextIO, cast from typing import Dict, Any, Iterable, Optional, List, TextIO, cast
@@ -9,14 +10,15 @@ from .bundles.bundle_room import BundleRoom
from .bundles.bundles import get_all_bundles from .bundles.bundles import get_all_bundles
from .content import StardewContent, create_content from .content import StardewContent, create_content
from .early_items import setup_early_items 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, generate_filler_choice_pool
from .locations import location_table, create_locations, LocationData, locations_by_tag from .locations import location_table, create_locations, LocationData, locations_by_tag
from .logic.logic import StardewLogic from .logic.logic import StardewLogic
from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, EnabledFillerBuffs, NumberOfMovementBuffs, \ from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, EnabledFillerBuffs, NumberOfMovementBuffs, \
BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization, FarmType BuildingProgression, EntranceRandomization, FarmType
from .options.forced_options import force_change_options_if_incompatible from .options.forced_options import force_change_options_if_incompatible
from .options.option_groups import sv_option_groups from .options.option_groups import sv_option_groups
from .options.presets import sv_options_presets from .options.presets import sv_options_presets
from .options.worlds_group import apply_most_restrictive_options
from .regions import create_regions from .regions import create_regions
from .rules import set_rules from .rules import set_rules
from .stardew_rule import True_, StardewRule, HasProgressionPercent from .stardew_rule import True_, StardewRule, HasProgressionPercent
@@ -89,6 +91,16 @@ class StardewValleyWorld(World):
total_progression_items: int total_progression_items: int
@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): def __init__(self, multiworld: MultiWorld, player: int):
super().__init__(multiworld, player) super().__init__(multiworld, player)
self.filler_item_pool_names = [] self.filler_item_pool_names = []
@@ -299,32 +311,9 @@ class StardewValleyWorld(World):
def get_filler_item_name(self) -> str: def get_filler_item_name(self) -> str:
if not self.filler_item_pool_names: 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) 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"]:
if self.multiworld.game[player] != self.game:
continue
player_options = cast(StardewValleyOptions, self.multiworld.worlds[player].options)
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: 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, """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.""" if as stage it's right under the common header before per-player options."""

View File

@@ -808,6 +808,16 @@ def remove_excluded_items_island_mods(items, exclude_ginger_island: bool, mods:
return mod_filter 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 [item.name for item in available_filler]
def remove_limited_amount_packs(packs): 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] return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.EXACTLY_TWO not in pack.groups]

View File

@@ -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)

View File

@@ -2,7 +2,7 @@ from unittest import TestCase
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from .option_assert import get_stardew_options from .option_assert import get_stardew_options
from ... import options, ExcludeGingerIsland from ... import options
def is_goal(multiworld: MultiWorld, goal: int) -> bool: def is_goal(multiworld: MultiWorld, goal: int) -> bool:
@@ -36,7 +36,7 @@ def is_not_perfection(multiworld: MultiWorld) -> bool:
class GoalAssertMixin(TestCase): class GoalAssertMixin(TestCase):
def assert_ginger_island_is_included(self, multiworld: MultiWorld): def assert_ginger_island_is_included(self, multiworld: MultiWorld):
self.assertEqual(get_stardew_options(multiworld).exclude_ginger_island, ExcludeGingerIsland.option_false) self.assertEqual(get_stardew_options(multiworld).exclude_ginger_island, options.ExcludeGingerIsland.option_false)
def assert_walnut_hunter_world_is_valid(self, multiworld: MultiWorld): def assert_walnut_hunter_world_is_valid(self, multiworld: MultiWorld):
if is_not_walnut_hunter(multiworld): if is_not_walnut_hunter(multiworld):

View File

@@ -2,7 +2,7 @@ from unittest import TestCase
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from .world_assert import get_all_item_names, get_all_location_names from .world_assert import get_all_item_names, get_all_location_names
from ... import StardewValleyWorld, options, item_table, Group, location_table, ExcludeGingerIsland from ... import StardewValleyWorld, options, item_table, Group, location_table
from ...locations import LocationTags from ...locations import LocationTags
from ...strings.ap_names.transport_names import Transportation from ...strings.ap_names.transport_names import Transportation
@@ -49,7 +49,7 @@ class OptionAssertMixin(TestCase):
def assert_can_reach_island_if_should(self, multiworld: MultiWorld): def assert_can_reach_island_if_should(self, multiworld: MultiWorld):
stardew_options = get_stardew_options(multiworld) stardew_options = get_stardew_options(multiworld)
include_island = stardew_options.exclude_ginger_island.value == ExcludeGingerIsland.option_false include_island = stardew_options.exclude_ginger_island.value == options.ExcludeGingerIsland.option_false
if include_island: if include_island:
self.assert_can_reach_island(multiworld) self.assert_can_reach_island(multiworld)
else: else: