From 51c4fe8f67511850a7d26fe07a183242683034f1 Mon Sep 17 00:00:00 2001 From: Jouramie <16137441+Jouramie@users.noreply.github.com> Date: Sun, 8 Dec 2024 21:00:30 -0500 Subject: [PATCH] Stardew Valley: Fix a bug where walnutsanity would get deactivated even tho ginger island got forced activated (and move some files) (#4311) --- worlds/stardew_valley/__init__.py | 40 +- worlds/stardew_valley/items.py | 32 +- worlds/stardew_valley/logic/walnut_logic.py | 22 +- worlds/stardew_valley/option_groups.py | 76 ---- worlds/stardew_valley/options/__init__.py | 6 + .../stardew_valley/options/forced_options.py | 48 +++ .../stardew_valley/options/option_groups.py | 68 ++++ .../stardew_valley/{ => options}/options.py | 23 +- worlds/stardew_valley/options/presets.py | 371 +++++++++++++++++ worlds/stardew_valley/presets.py | 376 ------------------ worlds/stardew_valley/rules.py | 10 +- .../strings/ap_names/ap_option_names.py | 35 +- .../strings/ap_names/mods/__init__.py | 0 worlds/stardew_valley/test/TestBooksanity.py | 1 - worlds/stardew_valley/test/TestOptions.py | 34 +- .../stardew_valley/test/TestOptionsPairs.py | 19 +- worlds/stardew_valley/test/TestRegions.py | 9 +- .../stardew_valley/test/TestWalnutsanity.py | 12 +- worlds/stardew_valley/test/__init__.py | 59 +-- worlds/stardew_valley/test/mods/TestMods.py | 5 +- .../test/options/TestForcedOptions.py | 84 ++++ .../test/{ => options}/TestPresets.py | 10 +- .../stardew_valley/test/options/__init__.py | 0 worlds/stardew_valley/test/options/utils.py | 68 ++++ .../test/stability/TestUniversalTracker.py | 4 +- 25 files changed, 752 insertions(+), 660 deletions(-) delete mode 100644 worlds/stardew_valley/option_groups.py create mode 100644 worlds/stardew_valley/options/__init__.py create mode 100644 worlds/stardew_valley/options/forced_options.py create mode 100644 worlds/stardew_valley/options/option_groups.py rename worlds/stardew_valley/{ => options}/options.py (97%) create mode 100644 worlds/stardew_valley/options/presets.py delete mode 100644 worlds/stardew_valley/presets.py create mode 100644 worlds/stardew_valley/strings/ap_names/mods/__init__.py create mode 100644 worlds/stardew_valley/test/options/TestForcedOptions.py rename worlds/stardew_valley/test/{ => options}/TestPresets.py (86%) create mode 100644 worlds/stardew_valley/test/options/__init__.py create mode 100644 worlds/stardew_valley/test/options/utils.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 34c617f5013a..6ba0e35e0a3a 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -3,7 +3,7 @@ from typing import Dict, Any, Iterable, Optional, Union, List, TextIO from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState -from Options import PerGameCommonOptions, Accessibility +from Options import PerGameCommonOptions from worlds.AutoWorld import World, WebWorld from . import rules from .bundles.bundle_room import BundleRoom @@ -15,10 +15,11 @@ from .logic.bundle_logic import BundleLogic from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS -from .option_groups import sv_option_groups -from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, EnabledFillerBuffs, NumberOfMovementBuffs, \ - BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization, FarmType, Walnutsanity -from .presets import sv_options_presets +from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, EnabledFillerBuffs, NumberOfMovementBuffs, \ + BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization, FarmType, Walnutsanity +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 .regions import create_regions from .rules import set_rules from .stardew_rule import True_, StardewRule, HasProgressionPercent, true_ @@ -112,36 +113,9 @@ def interpret_slot_data(self, slot_data: Dict[str, Any]) -> Optional[int]: return seed def generate_early(self): - self.force_change_options_if_incompatible() + force_change_options_if_incompatible(self.options, self.player, self.player_name) self.content = create_content(self.options) - def force_change_options_if_incompatible(self): - goal_is_walnut_hunter = self.options.goal == Goal.option_greatest_walnut_hunter - goal_is_perfection = self.options.goal == Goal.option_perfection - goal_is_island_related = goal_is_walnut_hunter or goal_is_perfection - exclude_ginger_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - - if goal_is_island_related and exclude_ginger_island: - self.options.exclude_ginger_island.value = ExcludeGingerIsland.option_false - goal_name = self.options.goal.current_key - logger.warning( - f"Goal '{goal_name}' requires Ginger Island. Exclude Ginger Island setting forced to 'False' for player {self.player} ({self.player_name})") - - if exclude_ginger_island and self.options.walnutsanity != Walnutsanity.preset_none: - self.options.walnutsanity.value = Walnutsanity.preset_none - logger.warning( - f"Walnutsanity requires Ginger Island. Ginger Island was excluded from {self.player} ({self.player_name})'s world, so walnutsanity was force disabled") - - if goal_is_perfection and self.options.accessibility == Accessibility.option_minimal: - self.options.accessibility.value = Accessibility.option_full - logger.warning( - f"Goal 'Perfection' requires full accessibility. Accessibility setting forced to 'Full' for player {self.player} ({self.player_name})") - - elif self.options.goal == Goal.option_allsanity and self.options.accessibility == Accessibility.option_minimal: - self.options.accessibility.value = Accessibility.option_full - logger.warning( - f"Goal 'Allsanity' requires full accessibility. Accessibility setting forced to 'Full' for player {self.player} ({self.player_name})") - def create_regions(self): def create_region(name: str, exits: Iterable[str]) -> Region: region = Region(name, self.player, self.multiworld) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 3d852a37f402..6ac827f869cc 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -17,7 +17,7 @@ from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Museumsanity, \ BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations, Monstersanity, Goal, \ Chefsanity, Craftsanity, BundleRandomization, EntranceRandomization, Shipsanity, Walnutsanity, EnabledFillerBuffs -from .strings.ap_names.ap_option_names import OptionName +from .strings.ap_names.ap_option_names import BuffOptionName, WalnutsanityOptionName from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.community_upgrade_names import CommunityUpgrade @@ -538,16 +538,16 @@ def create_walnuts(item_factory: StardewItemFactory, options: StardewValleyOptio num_penta_walnuts = 1 # https://stardewvalleywiki.com/Golden_Walnut # Totals should be accurate, but distribution is slightly offset to make room for baseline walnuts - if OptionName.walnutsanity_puzzles in walnutsanity: # 61 + if WalnutsanityOptionName.puzzles in walnutsanity: # 61 num_single_walnuts += 6 # 6 num_triple_walnuts += 5 # 15 num_penta_walnuts += 8 # 40 - if OptionName.walnutsanity_bushes in walnutsanity: # 25 + if WalnutsanityOptionName.bushes in walnutsanity: # 25 num_single_walnuts += 16 # 16 num_triple_walnuts += 3 # 9 - if OptionName.walnutsanity_dig_spots in walnutsanity: # 18 + if WalnutsanityOptionName.dig_spots in walnutsanity: # 18 num_single_walnuts += 18 # 18 - if OptionName.walnutsanity_repeatables in walnutsanity: # 33 + if WalnutsanityOptionName.repeatables in walnutsanity: # 33 num_single_walnuts += 30 # 30 num_triple_walnuts += 1 # 3 @@ -833,27 +833,27 @@ def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool) -> Li def get_allowed_player_buffs(buff_option: EnabledFillerBuffs) -> List[ItemData]: allowed_buffs = [] - if OptionName.buff_luck in buff_option: + if BuffOptionName.luck in buff_option: allowed_buffs.append(item_table[Buff.luck]) - if OptionName.buff_damage in buff_option: + if BuffOptionName.damage in buff_option: allowed_buffs.append(item_table[Buff.damage]) - if OptionName.buff_defense in buff_option: + if BuffOptionName.defense in buff_option: allowed_buffs.append(item_table[Buff.defense]) - if OptionName.buff_immunity in buff_option: + if BuffOptionName.immunity in buff_option: allowed_buffs.append(item_table[Buff.immunity]) - if OptionName.buff_health in buff_option: + if BuffOptionName.health in buff_option: allowed_buffs.append(item_table[Buff.health]) - if OptionName.buff_energy in buff_option: + if BuffOptionName.energy in buff_option: allowed_buffs.append(item_table[Buff.energy]) - if OptionName.buff_bite in buff_option: + if BuffOptionName.bite in buff_option: allowed_buffs.append(item_table[Buff.bite_rate]) - if OptionName.buff_fish_trap in buff_option: + if BuffOptionName.fish_trap in buff_option: allowed_buffs.append(item_table[Buff.fish_trap]) - if OptionName.buff_fishing_bar in buff_option: + if BuffOptionName.fishing_bar in buff_option: allowed_buffs.append(item_table[Buff.fishing_bar]) - if OptionName.buff_quality in buff_option: + if BuffOptionName.quality in buff_option: allowed_buffs.append(item_table[Buff.quality]) - if OptionName.buff_glow in buff_option: + if BuffOptionName.glow in buff_option: allowed_buffs.append(item_table[Buff.glow]) return allowed_buffs diff --git a/worlds/stardew_valley/logic/walnut_logic.py b/worlds/stardew_valley/logic/walnut_logic.py index 14fe1c339090..4ab3b46f70d9 100644 --- a/worlds/stardew_valley/logic/walnut_logic.py +++ b/worlds/stardew_valley/logic/walnut_logic.py @@ -7,10 +7,10 @@ from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from ..strings.ap_names.event_names import Event from ..options import ExcludeGingerIsland, Walnutsanity from ..stardew_rule import StardewRule, False_, True_ -from ..strings.ap_names.ap_option_names import OptionName +from ..strings.ap_names.ap_option_names import WalnutsanityOptionName +from ..strings.ap_names.event_names import Event from ..strings.craftable_names import Furniture from ..strings.crop_names import Fruit from ..strings.metal_names import Mineral, Fossil @@ -25,7 +25,7 @@ def __init__(self, *args, **kwargs): class WalnutLogic(BaseLogic[Union[WalnutLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, CombatLogicMixin, - AbilityLogicMixin]]): +AbilityLogicMixin]]): def has_walnut(self, number: int) -> StardewRule: if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: @@ -44,22 +44,22 @@ def has_walnut(self, number: int) -> StardewRule: total_walnuts = puzzle_walnuts + bush_walnuts + dig_walnuts + repeatable_walnuts walnuts_to_receive = 0 walnuts_to_collect = number - if OptionName.walnutsanity_puzzles in self.options.walnutsanity: + if WalnutsanityOptionName.puzzles in self.options.walnutsanity: puzzle_walnut_rate = puzzle_walnuts / total_walnuts puzzle_walnuts_required = round(puzzle_walnut_rate * number) walnuts_to_receive += puzzle_walnuts_required walnuts_to_collect -= puzzle_walnuts_required - if OptionName.walnutsanity_bushes in self.options.walnutsanity: + if WalnutsanityOptionName.bushes in self.options.walnutsanity: bush_walnuts_rate = bush_walnuts / total_walnuts bush_walnuts_required = round(bush_walnuts_rate * number) walnuts_to_receive += bush_walnuts_required walnuts_to_collect -= bush_walnuts_required - if OptionName.walnutsanity_dig_spots in self.options.walnutsanity: + if WalnutsanityOptionName.dig_spots in self.options.walnutsanity: dig_walnuts_rate = dig_walnuts / total_walnuts dig_walnuts_required = round(dig_walnuts_rate * number) walnuts_to_receive += dig_walnuts_required walnuts_to_collect -= dig_walnuts_required - if OptionName.walnutsanity_repeatables in self.options.walnutsanity: + if WalnutsanityOptionName.repeatables in self.options.walnutsanity: repeatable_walnuts_rate = repeatable_walnuts / total_walnuts repeatable_walnuts_required = round(repeatable_walnuts_rate * number) walnuts_to_receive += repeatable_walnuts_required @@ -104,9 +104,9 @@ def can_get_walnuts(self, number: int) -> StardewRule: return reach_entire_island gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz) return reach_entire_island & self.logic.has(Fruit.banana) & self.logic.has_all(*gems) & \ - self.logic.ability.can_mine_perfectly() & self.logic.ability.can_fish_perfectly() & \ - self.logic.has(Furniture.flute_block) & self.logic.has(Seed.melon) & self.logic.has(Seed.wheat) & \ - self.logic.has(Seed.garlic) & self.can_complete_field_office() + self.logic.ability.can_mine_perfectly() & self.logic.ability.can_fish_perfectly() & \ + self.logic.has(Furniture.flute_block) & self.logic.has(Seed.melon) & self.logic.has(Seed.wheat) & \ + self.logic.has(Seed.garlic) & self.can_complete_field_office() @cached_property def can_start_field_office(self) -> StardewRule: @@ -132,4 +132,4 @@ def can_complete_bat_collection(self) -> StardewRule: def can_complete_field_office(self) -> StardewRule: return self.can_complete_large_animal_collection() & self.can_complete_snake_collection() & \ - self.can_complete_frog_collection() & self.can_complete_bat_collection() + self.can_complete_frog_collection() & self.can_complete_bat_collection() diff --git a/worlds/stardew_valley/option_groups.py b/worlds/stardew_valley/option_groups.py deleted file mode 100644 index d0f052348a7e..000000000000 --- a/worlds/stardew_valley/option_groups.py +++ /dev/null @@ -1,76 +0,0 @@ -import logging - -from Options import DeathLink, ProgressionBalancing, Accessibility -from .options import (Goal, StartingMoney, ProfitMargin, BundleRandomization, BundlePrice, - EntranceRandomization, SeasonRandomization, Cropsanity, BackpackProgression, - ToolProgression, ElevatorProgression, SkillProgression, BuildingProgression, - FestivalLocations, ArcadeMachineLocations, SpecialOrderLocations, - QuestLocations, Fishsanity, Museumsanity, Friendsanity, FriendsanityHeartSize, - NumberOfMovementBuffs, EnabledFillerBuffs, ExcludeGingerIsland, TrapItems, - MultipleDaySleepEnabled, MultipleDaySleepCost, ExperienceMultiplier, - FriendshipMultiplier, DebrisMultiplier, QuickStart, Gifting, FarmType, - Monstersanity, Shipsanity, Cooksanity, Chefsanity, Craftsanity, Mods, Booksanity, Walnutsanity, BundlePlando) - -sv_option_groups = [] -try: - from Options import OptionGroup -except: - logging.warning("Old AP Version, OptionGroup not available.") -else: - sv_option_groups = [ - OptionGroup("General", [ - Goal, - FarmType, - BundleRandomization, - BundlePrice, - EntranceRandomization, - ExcludeGingerIsland, - ]), - OptionGroup("Major Unlocks", [ - SeasonRandomization, - Cropsanity, - BackpackProgression, - ToolProgression, - ElevatorProgression, - SkillProgression, - BuildingProgression, - ]), - OptionGroup("Extra Shuffling", [ - FestivalLocations, - ArcadeMachineLocations, - SpecialOrderLocations, - QuestLocations, - Fishsanity, - Museumsanity, - Friendsanity, - FriendsanityHeartSize, - Monstersanity, - Shipsanity, - Cooksanity, - Chefsanity, - Craftsanity, - Booksanity, - Walnutsanity, - ]), - OptionGroup("Multipliers and Buffs", [ - StartingMoney, - ProfitMargin, - ExperienceMultiplier, - FriendshipMultiplier, - DebrisMultiplier, - NumberOfMovementBuffs, - EnabledFillerBuffs, - TrapItems, - MultipleDaySleepEnabled, - MultipleDaySleepCost, - QuickStart, - ]), - OptionGroup("Advanced Options", [ - Gifting, - DeathLink, - Mods, - BundlePlando, - ProgressionBalancing, - Accessibility, - ]), - ] diff --git a/worlds/stardew_valley/options/__init__.py b/worlds/stardew_valley/options/__init__.py new file mode 100644 index 000000000000..d1436b00dff7 --- /dev/null +++ b/worlds/stardew_valley/options/__init__.py @@ -0,0 +1,6 @@ +from .options import StardewValleyOption, Goal, FarmType, StartingMoney, ProfitMargin, BundleRandomization, BundlePrice, EntranceRandomization, \ + SeasonRandomization, Cropsanity, BackpackProgression, ToolProgression, ElevatorProgression, SkillProgression, BuildingProgression, FestivalLocations, \ + ArcadeMachineLocations, SpecialOrderLocations, QuestLocations, Fishsanity, Museumsanity, Monstersanity, Shipsanity, Cooksanity, Chefsanity, Craftsanity, \ + Friendsanity, FriendsanityHeartSize, Booksanity, Walnutsanity, NumberOfMovementBuffs, EnabledFillerBuffs, ExcludeGingerIsland, TrapItems, \ + MultipleDaySleepEnabled, MultipleDaySleepCost, ExperienceMultiplier, FriendshipMultiplier, DebrisMultiplier, QuickStart, Gifting, Mods, BundlePlando, \ + StardewValleyOptions diff --git a/worlds/stardew_valley/options/forced_options.py b/worlds/stardew_valley/options/forced_options.py new file mode 100644 index 000000000000..84cdc936b3f1 --- /dev/null +++ b/worlds/stardew_valley/options/forced_options.py @@ -0,0 +1,48 @@ +import logging + +import Options as ap_options +from . import options + +logger = logging.getLogger(__name__) + + +def force_change_options_if_incompatible(world_options: options.StardewValleyOptions, player: int, player_name: str) -> None: + force_ginger_island_inclusion_when_goal_is_ginger_island_related(world_options, player, player_name) + force_walnutsanity_deactivation_when_ginger_island_is_excluded(world_options, player, player_name) + force_accessibility_to_full_when_goal_requires_all_locations(player, player_name, world_options) + + +def force_ginger_island_inclusion_when_goal_is_ginger_island_related(world_options: options.StardewValleyOptions, player: int, player_name: str) -> None: + goal_is_walnut_hunter = world_options.goal == options.Goal.option_greatest_walnut_hunter + goal_is_perfection = world_options.goal == options.Goal.option_perfection + goal_is_island_related = goal_is_walnut_hunter or goal_is_perfection + ginger_island_is_excluded = world_options.exclude_ginger_island == options.ExcludeGingerIsland.option_true + + if goal_is_island_related and ginger_island_is_excluded: + world_options.exclude_ginger_island.value = options.ExcludeGingerIsland.option_false + goal_name = world_options.goal.current_option_name + logger.warning(f"Goal '{goal_name}' requires Ginger Island. " + f"Exclude Ginger Island option forced to 'False' for player {player} ({player_name})") + + +def force_walnutsanity_deactivation_when_ginger_island_is_excluded(world_options: options.StardewValleyOptions, player: int, player_name: str): + ginger_island_is_excluded = world_options.exclude_ginger_island == options.ExcludeGingerIsland.option_true + walnutsanity_is_active = world_options.walnutsanity != options.Walnutsanity.preset_none + + if ginger_island_is_excluded and walnutsanity_is_active: + world_options.walnutsanity.value = options.Walnutsanity.preset_none + logger.warning(f"Walnutsanity requires Ginger Island. " + f"Ginger Island was excluded from {player} ({player_name})'s world, so walnutsanity was force disabled") + + +def force_accessibility_to_full_when_goal_requires_all_locations(player, player_name, world_options): + goal_is_allsanity = world_options.goal == options.Goal.option_allsanity + goal_is_perfection = world_options.goal == options.Goal.option_perfection + goal_requires_all_locations = goal_is_allsanity or goal_is_perfection + accessibility_is_minimal = world_options.accessibility == ap_options.Accessibility.option_minimal + + if goal_requires_all_locations and accessibility_is_minimal: + world_options.accessibility.value = ap_options.Accessibility.option_full + goal_name = world_options.goal.current_option_name + logger.warning(f"Goal '{goal_name}' requires full accessibility. " + f"Accessibility option forced to 'Full' for player {player} ({player_name})") diff --git a/worlds/stardew_valley/options/option_groups.py b/worlds/stardew_valley/options/option_groups.py new file mode 100644 index 000000000000..bcb9bee77ff4 --- /dev/null +++ b/worlds/stardew_valley/options/option_groups.py @@ -0,0 +1,68 @@ +import logging + +import Options as ap_options +from . import options + +sv_option_groups = [] +try: + from Options import OptionGroup +except ImportError: + logging.warning("Old AP Version, OptionGroup not available.") +else: + sv_option_groups = [ + OptionGroup("General", [ + options.Goal, + options.FarmType, + options.BundleRandomization, + options.BundlePrice, + options.EntranceRandomization, + options.ExcludeGingerIsland, + ]), + OptionGroup("Major Unlocks", [ + options.SeasonRandomization, + options.Cropsanity, + options.BackpackProgression, + options.ToolProgression, + options.ElevatorProgression, + options.SkillProgression, + options.BuildingProgression, + ]), + OptionGroup("Extra Shuffling", [ + options.FestivalLocations, + options.ArcadeMachineLocations, + options.SpecialOrderLocations, + options.QuestLocations, + options.Fishsanity, + options.Museumsanity, + options.Friendsanity, + options.FriendsanityHeartSize, + options.Monstersanity, + options.Shipsanity, + options.Cooksanity, + options.Chefsanity, + options.Craftsanity, + options.Booksanity, + options.Walnutsanity, + ]), + OptionGroup("Multipliers and Buffs", [ + options.StartingMoney, + options.ProfitMargin, + options.ExperienceMultiplier, + options.FriendshipMultiplier, + options.DebrisMultiplier, + options.NumberOfMovementBuffs, + options.EnabledFillerBuffs, + options.TrapItems, + options.MultipleDaySleepEnabled, + options.MultipleDaySleepCost, + options.QuickStart, + ]), + OptionGroup("Advanced Options", [ + options.Gifting, + ap_options.DeathLink, + options.Mods, + options.BundlePlando, + ap_options.ProgressionBalancing, + ap_options.Accessibility, + ]), + ] diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options/options.py similarity index 97% rename from worlds/stardew_valley/options.py rename to worlds/stardew_valley/options/options.py index 5369e88a2dcb..5d3b25b4da13 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options/options.py @@ -4,9 +4,9 @@ from typing import Protocol, ClassVar from Options import Range, NamedRange, Toggle, Choice, OptionSet, PerGameCommonOptions, DeathLink, OptionList, Visibility -from .mods.mod_data import ModNames -from .strings.ap_names.ap_option_names import OptionName -from .strings.bundle_names import all_cc_bundle_names +from ..mods.mod_data import ModNames +from ..strings.ap_names.ap_option_names import BuffOptionName, WalnutsanityOptionName +from ..strings.bundle_names import all_cc_bundle_names class StardewValleyOption(Protocol): @@ -582,8 +582,10 @@ class Walnutsanity(OptionSet): """ internal_name = "walnutsanity" display_name = "Walnutsanity" - valid_keys = frozenset({OptionName.walnutsanity_puzzles, OptionName.walnutsanity_bushes, OptionName.walnutsanity_dig_spots, - OptionName.walnutsanity_repeatables, }) + valid_keys = frozenset({ + WalnutsanityOptionName.puzzles, WalnutsanityOptionName.bushes, WalnutsanityOptionName.dig_spots, + WalnutsanityOptionName.repeatables, + }) preset_none = frozenset() preset_all = valid_keys default = preset_none @@ -622,12 +624,14 @@ class EnabledFillerBuffs(OptionSet): """ internal_name = "enabled_filler_buffs" display_name = "Enabled Filler Buffs" - valid_keys = frozenset({OptionName.buff_luck, OptionName.buff_damage, OptionName.buff_defense, OptionName.buff_immunity, OptionName.buff_health, - OptionName.buff_energy, OptionName.buff_bite, OptionName.buff_fish_trap, OptionName.buff_fishing_bar}) - # OptionName.buff_quality, OptionName.buff_glow}) # Disabled these two buffs because they are too hard to make on the mod side + valid_keys = frozenset({ + BuffOptionName.luck, BuffOptionName.damage, BuffOptionName.defense, BuffOptionName.immunity, BuffOptionName.health, + BuffOptionName.energy, BuffOptionName.bite, BuffOptionName.fish_trap, BuffOptionName.fishing_bar, + }) + # OptionName.buff_quality, OptionName.buff_glow}) # Disabled these two buffs because they are too hard to make on the mod side preset_none = frozenset() preset_all = valid_keys - default = frozenset({OptionName.buff_luck, OptionName.buff_defense, OptionName.buff_bite}) + default = frozenset({BuffOptionName.luck, BuffOptionName.defense, BuffOptionName.bite}) class ExcludeGingerIsland(Toggle): @@ -762,7 +766,6 @@ class Gifting(Toggle): ModNames.wellwick, ModNames.shiko, ModNames.delores, ModNames.riley, ModNames.boarding_house} - if 'unittest' in sys.modules.keys() or 'pytest' in sys.modules.keys(): disabled_mods = {} diff --git a/worlds/stardew_valley/options/presets.py b/worlds/stardew_valley/options/presets.py new file mode 100644 index 000000000000..c2c210e5ca6e --- /dev/null +++ b/worlds/stardew_valley/options/presets.py @@ -0,0 +1,371 @@ +from typing import Any, Dict + +import Options as ap_options +from . import options +from ..strings.ap_names.ap_option_names import WalnutsanityOptionName + +# @formatter:off +all_random_settings = { + "progression_balancing": "random", + "accessibility": "random", + options.Goal.internal_name: "random", + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "random", + options.ProfitMargin.internal_name: "random", + options.BundleRandomization.internal_name: "random", + options.BundlePrice.internal_name: "random", + options.EntranceRandomization.internal_name: "random", + options.SeasonRandomization.internal_name: "random", + options.Cropsanity.internal_name: "random", + options.BackpackProgression.internal_name: "random", + options.ToolProgression.internal_name: "random", + options.ElevatorProgression.internal_name: "random", + options.SkillProgression.internal_name: "random", + options.BuildingProgression.internal_name: "random", + options.FestivalLocations.internal_name: "random", + options.ArcadeMachineLocations.internal_name: "random", + options.SpecialOrderLocations.internal_name: "random", + options.QuestLocations.internal_name: "random", + options.Fishsanity.internal_name: "random", + options.Museumsanity.internal_name: "random", + options.Monstersanity.internal_name: "random", + options.Shipsanity.internal_name: "random", + options.Cooksanity.internal_name: "random", + options.Chefsanity.internal_name: "random", + options.Craftsanity.internal_name: "random", + options.Friendsanity.internal_name: "random", + options.FriendsanityHeartSize.internal_name: "random", + options.Booksanity.internal_name: "random", + options.NumberOfMovementBuffs.internal_name: "random", + options.ExcludeGingerIsland.internal_name: "random", + options.TrapItems.internal_name: "random", + options.MultipleDaySleepEnabled.internal_name: "random", + options.MultipleDaySleepCost.internal_name: "random", + options.ExperienceMultiplier.internal_name: "random", + options.FriendshipMultiplier.internal_name: "random", + options.DebrisMultiplier.internal_name: "random", + options.QuickStart.internal_name: "random", + options.Gifting.internal_name: "random", + "death_link": "random", +} + +easy_settings = { + options.Goal.internal_name: options.Goal.option_community_center, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "very rich", + options.ProfitMargin.internal_name: "double", + options.BundleRandomization.internal_name: options.BundleRandomization.option_thematic, + options.BundlePrice.internal_name: options.BundlePrice.option_cheap, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_disabled, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive_very_cheap, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_very_cheap, + options.FestivalLocations.internal_name: options.FestivalLocations.option_easy, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_vanilla_very_short, + options.QuestLocations.internal_name: "minimum", + options.Fishsanity.internal_name: options.Fishsanity.option_only_easy_fish, + options.Museumsanity.internal_name: options.Museumsanity.option_milestones, + options.Monstersanity.internal_name: options.Monstersanity.option_one_per_category, + options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Cooksanity.internal_name: options.Cooksanity.option_none, + options.Chefsanity.internal_name: options.Chefsanity.option_none, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_none, + options.FriendsanityHeartSize.internal_name: 4, + options.Booksanity.internal_name: options.Booksanity.option_none, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_none, + options.NumberOfMovementBuffs.internal_name: 8, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: options.TrapItems.option_easy, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.option_true, + options.MultipleDaySleepCost.internal_name: "free", + options.ExperienceMultiplier.internal_name: "triple", + options.FriendshipMultiplier.internal_name: "quadruple", + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.option_quarter, + options.QuickStart.internal_name: options.QuickStart.option_true, + options.Gifting.internal_name: options.Gifting.option_true, + "death_link": "false", +} + +medium_settings = { + options.Goal.internal_name: options.Goal.option_community_center, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "rich", + options.ProfitMargin.internal_name: 150, + options.BundleRandomization.internal_name: options.BundleRandomization.option_remixed, + options.BundlePrice.internal_name: options.BundlePrice.option_normal, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_non_progression, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive_cheap, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_cheap, + options.FestivalLocations.internal_name: options.FestivalLocations.option_hard, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_victories_easy, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_short, + options.QuestLocations.internal_name: "normal", + options.Fishsanity.internal_name: options.Fishsanity.option_exclude_legendaries, + options.Museumsanity.internal_name: options.Museumsanity.option_milestones, + options.Monstersanity.internal_name: options.Monstersanity.option_one_per_monster, + options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Cooksanity.internal_name: options.Cooksanity.option_none, + options.Chefsanity.internal_name: options.Chefsanity.option_queen_of_sauce, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_starting_npcs, + options.FriendsanityHeartSize.internal_name: 4, + options.Booksanity.internal_name: options.Booksanity.option_power_skill, + options.Walnutsanity.internal_name: [WalnutsanityOptionName.puzzles], + options.NumberOfMovementBuffs.internal_name: 6, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: options.TrapItems.option_medium, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.option_true, + options.MultipleDaySleepCost.internal_name: "free", + options.ExperienceMultiplier.internal_name: "double", + options.FriendshipMultiplier.internal_name: "triple", + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.option_half, + options.QuickStart.internal_name: options.QuickStart.option_true, + options.Gifting.internal_name: options.Gifting.option_true, + "death_link": "false", +} + +hard_settings = { + options.Goal.internal_name: options.Goal.option_grandpa_evaluation, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "extra", + options.ProfitMargin.internal_name: "normal", + options.BundleRandomization.internal_name: options.BundleRandomization.option_remixed, + options.BundlePrice.internal_name: options.BundlePrice.option_expensive, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_buildings_without_house, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive_from_previous_floor, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive_with_masteries, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.FestivalLocations.internal_name: options.FestivalLocations.option_hard, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi_short, + options.QuestLocations.internal_name: "lots", + options.Fishsanity.internal_name: options.Fishsanity.option_all, + options.Museumsanity.internal_name: options.Museumsanity.option_all, + options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals, + options.Shipsanity.internal_name: options.Shipsanity.option_crops, + options.Cooksanity.internal_name: options.Cooksanity.option_queen_of_sauce, + options.Chefsanity.internal_name: options.Chefsanity.option_qos_and_purchases, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_all, + options.FriendsanityHeartSize.internal_name: 4, + options.Booksanity.internal_name: options.Booksanity.option_all, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_all, + options.NumberOfMovementBuffs.internal_name: 4, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.default, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false, + options.TrapItems.internal_name: options.TrapItems.option_hard, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.option_true, + options.MultipleDaySleepCost.internal_name: "cheap", + options.ExperienceMultiplier.internal_name: "vanilla", + options.FriendshipMultiplier.internal_name: "double", + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.option_vanilla, + options.QuickStart.internal_name: options.QuickStart.option_true, + options.Gifting.internal_name: options.Gifting.option_true, + "death_link": "true", +} + +nightmare_settings = { + options.Goal.internal_name: options.Goal.option_community_center, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "vanilla", + options.ProfitMargin.internal_name: "half", + options.BundleRandomization.internal_name: options.BundleRandomization.option_shuffled, + options.BundlePrice.internal_name: options.BundlePrice.option_very_expensive, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_buildings, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive_from_previous_floor, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive_with_masteries, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.FestivalLocations.internal_name: options.FestivalLocations.option_hard, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, + options.QuestLocations.internal_name: "maximum", + options.Fishsanity.internal_name: options.Fishsanity.option_special, + options.Museumsanity.internal_name: options.Museumsanity.option_all, + options.Monstersanity.internal_name: options.Monstersanity.option_split_goals, + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, + options.Cooksanity.internal_name: options.Cooksanity.option_queen_of_sauce, + options.Chefsanity.internal_name: options.Chefsanity.option_qos_and_purchases, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, + options.FriendsanityHeartSize.internal_name: 4, + options.Booksanity.internal_name: options.Booksanity.option_all, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_all, + options.NumberOfMovementBuffs.internal_name: 2, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_none, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false, + options.TrapItems.internal_name: options.TrapItems.option_hell, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.option_true, + options.MultipleDaySleepCost.internal_name: "expensive", + options.ExperienceMultiplier.internal_name: "half", + options.FriendshipMultiplier.internal_name: "vanilla", + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.option_vanilla, + options.QuickStart.internal_name: options.QuickStart.option_false, + options.Gifting.internal_name: options.Gifting.option_true, + "death_link": "true", +} + +short_settings = { + options.Goal.internal_name: options.Goal.option_bottom_of_the_mines, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: "filthy rich", + options.ProfitMargin.internal_name: "quadruple", + options.BundleRandomization.internal_name: options.BundleRandomization.option_remixed, + options.BundlePrice.internal_name: options.BundlePrice.option_minimum, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_disabled, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter, + options.Cropsanity.internal_name: options.Cropsanity.option_disabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive_very_cheap, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_very_cheap, + options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_vanilla_very_short, + options.QuestLocations.internal_name: "none", + options.Fishsanity.internal_name: options.Fishsanity.option_none, + options.Museumsanity.internal_name: options.Museumsanity.option_none, + options.Monstersanity.internal_name: options.Monstersanity.option_none, + options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Cooksanity.internal_name: options.Cooksanity.option_none, + options.Chefsanity.internal_name: options.Chefsanity.option_none, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_none, + options.FriendsanityHeartSize.internal_name: 4, + options.Booksanity.internal_name: options.Booksanity.option_none, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_none, + options.NumberOfMovementBuffs.internal_name: 10, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: options.TrapItems.option_easy, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.option_true, + options.MultipleDaySleepCost.internal_name: "free", + options.ExperienceMultiplier.internal_name: "quadruple", + options.FriendshipMultiplier.internal_name: 800, + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.option_none, + options.QuickStart.internal_name: options.QuickStart.option_true, + options.Gifting.internal_name: options.Gifting.option_true, + "death_link": "false", +} + +minsanity_settings = { + options.Goal.internal_name: options.Goal.default, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: options.StartingMoney.default, + options.ProfitMargin.internal_name: options.ProfitMargin.default, + options.BundleRandomization.internal_name: options.BundleRandomization.default, + options.BundlePrice.internal_name: options.BundlePrice.default, + options.EntranceRandomization.internal_name: options.EntranceRandomization.default, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_disabled, + options.Cropsanity.internal_name: options.Cropsanity.option_disabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla, + options.ToolProgression.internal_name: options.ToolProgression.option_vanilla, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_vanilla, + options.SkillProgression.internal_name: options.SkillProgression.option_vanilla, + options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla, + options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_vanilla_very_short, + options.QuestLocations.internal_name: "none", + options.Fishsanity.internal_name: options.Fishsanity.option_none, + options.Museumsanity.internal_name: options.Museumsanity.option_none, + options.Monstersanity.internal_name: options.Monstersanity.option_none, + options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Cooksanity.internal_name: options.Cooksanity.option_none, + options.Chefsanity.internal_name: options.Chefsanity.option_none, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_none, + options.FriendsanityHeartSize.internal_name: options.FriendsanityHeartSize.default, + options.Booksanity.internal_name: options.Booksanity.option_none, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_none, + options.NumberOfMovementBuffs.internal_name: options.NumberOfMovementBuffs.default, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.default, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: options.TrapItems.default, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.default, + options.MultipleDaySleepCost.internal_name: options.MultipleDaySleepCost.default, + options.ExperienceMultiplier.internal_name: options.ExperienceMultiplier.default, + options.FriendshipMultiplier.internal_name: options.FriendshipMultiplier.default, + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.default, + options.QuickStart.internal_name: options.QuickStart.default, + options.Gifting.internal_name: options.Gifting.default, + "death_link": ap_options.DeathLink.default, +} + +allsanity_settings = { + options.Goal.internal_name: options.Goal.default, + options.FarmType.internal_name: "random", + options.StartingMoney.internal_name: options.StartingMoney.default, + options.ProfitMargin.internal_name: options.ProfitMargin.default, + options.BundleRandomization.internal_name: options.BundleRandomization.default, + options.BundlePrice.internal_name: options.BundlePrice.default, + options.EntranceRandomization.internal_name: options.EntranceRandomization.option_buildings, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, + options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive_with_masteries, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.FestivalLocations.internal_name: options.FestivalLocations.option_hard, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, + options.QuestLocations.internal_name: "maximum", + options.Fishsanity.internal_name: options.Fishsanity.option_all, + options.Museumsanity.internal_name: options.Museumsanity.option_all, + options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals, + options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Cooksanity.internal_name: options.Cooksanity.option_all, + options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.Craftsanity.internal_name: options.Craftsanity.option_all, + options.Friendsanity.internal_name: options.Friendsanity.option_all, + options.FriendsanityHeartSize.internal_name: 1, + options.Booksanity.internal_name: options.Booksanity.option_all, + options.Walnutsanity.internal_name: options.Walnutsanity.preset_all, + options.NumberOfMovementBuffs.internal_name: 12, + options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false, + options.TrapItems.internal_name: options.TrapItems.default, + options.MultipleDaySleepEnabled.internal_name: options.MultipleDaySleepEnabled.default, + options.MultipleDaySleepCost.internal_name: options.MultipleDaySleepCost.default, + options.ExperienceMultiplier.internal_name: options.ExperienceMultiplier.default, + options.FriendshipMultiplier.internal_name: options.FriendshipMultiplier.default, + options.DebrisMultiplier.internal_name: options.DebrisMultiplier.default, + options.QuickStart.internal_name: options.QuickStart.default, + options.Gifting.internal_name: options.Gifting.default, + "death_link": ap_options.DeathLink.default, +} +# @formatter:on + + +sv_options_presets: Dict[str, Dict[str, Any]] = { + "All random": all_random_settings, + "Easy": easy_settings, + "Medium": medium_settings, + "Hard": hard_settings, + "Nightmare": nightmare_settings, + "Short": short_settings, + "Minsanity": minsanity_settings, + "Allsanity": allsanity_settings, +} diff --git a/worlds/stardew_valley/presets.py b/worlds/stardew_valley/presets.py deleted file mode 100644 index 62672f29e424..000000000000 --- a/worlds/stardew_valley/presets.py +++ /dev/null @@ -1,376 +0,0 @@ -from typing import Any, Dict - -from Options import Accessibility, ProgressionBalancing, DeathLink -from .options import Goal, StartingMoney, ProfitMargin, BundleRandomization, BundlePrice, EntranceRandomization, SeasonRandomization, Cropsanity, \ - BackpackProgression, ToolProgression, ElevatorProgression, SkillProgression, BuildingProgression, FestivalLocations, ArcadeMachineLocations, \ - SpecialOrderLocations, QuestLocations, Fishsanity, Museumsanity, Friendsanity, FriendsanityHeartSize, NumberOfMovementBuffs, ExcludeGingerIsland, TrapItems, \ - MultipleDaySleepEnabled, MultipleDaySleepCost, ExperienceMultiplier, FriendshipMultiplier, DebrisMultiplier, QuickStart, \ - Gifting, FarmType, Monstersanity, Shipsanity, Cooksanity, Chefsanity, Craftsanity, Booksanity, Walnutsanity, EnabledFillerBuffs - -# @formatter:off -from .strings.ap_names.ap_option_names import OptionName - -all_random_settings = { - "progression_balancing": "random", - "accessibility": "random", - Goal.internal_name: "random", - FarmType.internal_name: "random", - StartingMoney.internal_name: "random", - ProfitMargin.internal_name: "random", - BundleRandomization.internal_name: "random", - BundlePrice.internal_name: "random", - EntranceRandomization.internal_name: "random", - SeasonRandomization.internal_name: "random", - Cropsanity.internal_name: "random", - BackpackProgression.internal_name: "random", - ToolProgression.internal_name: "random", - ElevatorProgression.internal_name: "random", - SkillProgression.internal_name: "random", - BuildingProgression.internal_name: "random", - FestivalLocations.internal_name: "random", - ArcadeMachineLocations.internal_name: "random", - SpecialOrderLocations.internal_name: "random", - QuestLocations.internal_name: "random", - Fishsanity.internal_name: "random", - Museumsanity.internal_name: "random", - Monstersanity.internal_name: "random", - Shipsanity.internal_name: "random", - Cooksanity.internal_name: "random", - Chefsanity.internal_name: "random", - Craftsanity.internal_name: "random", - Friendsanity.internal_name: "random", - FriendsanityHeartSize.internal_name: "random", - Booksanity.internal_name: "random", - NumberOfMovementBuffs.internal_name: "random", - ExcludeGingerIsland.internal_name: "random", - TrapItems.internal_name: "random", - MultipleDaySleepEnabled.internal_name: "random", - MultipleDaySleepCost.internal_name: "random", - ExperienceMultiplier.internal_name: "random", - FriendshipMultiplier.internal_name: "random", - DebrisMultiplier.internal_name: "random", - QuickStart.internal_name: "random", - Gifting.internal_name: "random", - "death_link": "random", -} - -easy_settings = { - Goal.internal_name: Goal.option_community_center, - FarmType.internal_name: "random", - StartingMoney.internal_name: "very rich", - ProfitMargin.internal_name: "double", - BundleRandomization.internal_name: BundleRandomization.option_thematic, - BundlePrice.internal_name: BundlePrice.option_cheap, - EntranceRandomization.internal_name: EntranceRandomization.option_disabled, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized_not_winter, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive_very_cheap, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive, - SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, - FestivalLocations.internal_name: FestivalLocations.option_easy, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_vanilla_very_short, - QuestLocations.internal_name: "minimum", - Fishsanity.internal_name: Fishsanity.option_only_easy_fish, - Museumsanity.internal_name: Museumsanity.option_milestones, - Monstersanity.internal_name: Monstersanity.option_one_per_category, - Shipsanity.internal_name: Shipsanity.option_none, - Cooksanity.internal_name: Cooksanity.option_none, - Chefsanity.internal_name: Chefsanity.option_none, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_none, - FriendsanityHeartSize.internal_name: 4, - Booksanity.internal_name: Booksanity.option_none, - Walnutsanity.internal_name: Walnutsanity.preset_none, - NumberOfMovementBuffs.internal_name: 8, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.preset_all, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.option_easy, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.option_true, - MultipleDaySleepCost.internal_name: "free", - ExperienceMultiplier.internal_name: "triple", - FriendshipMultiplier.internal_name: "quadruple", - DebrisMultiplier.internal_name: DebrisMultiplier.option_quarter, - QuickStart.internal_name: QuickStart.option_true, - Gifting.internal_name: Gifting.option_true, - "death_link": "false", -} - -medium_settings = { - Goal.internal_name: Goal.option_community_center, - FarmType.internal_name: "random", - StartingMoney.internal_name: "rich", - ProfitMargin.internal_name: 150, - BundleRandomization.internal_name: BundleRandomization.option_remixed, - BundlePrice.internal_name: BundlePrice.option_normal, - EntranceRandomization.internal_name: EntranceRandomization.option_non_progression, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive_cheap, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive, - SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_cheap, - FestivalLocations.internal_name: FestivalLocations.option_hard, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_victories_easy, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_short, - QuestLocations.internal_name: "normal", - Fishsanity.internal_name: Fishsanity.option_exclude_legendaries, - Museumsanity.internal_name: Museumsanity.option_milestones, - Monstersanity.internal_name: Monstersanity.option_one_per_monster, - Shipsanity.internal_name: Shipsanity.option_none, - Cooksanity.internal_name: Cooksanity.option_none, - Chefsanity.internal_name: Chefsanity.option_queen_of_sauce, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_starting_npcs, - FriendsanityHeartSize.internal_name: 4, - Booksanity.internal_name: Booksanity.option_power_skill, - Walnutsanity.internal_name: [OptionName.walnutsanity_puzzles], - NumberOfMovementBuffs.internal_name: 6, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.preset_all, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.option_medium, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.option_true, - MultipleDaySleepCost.internal_name: "free", - ExperienceMultiplier.internal_name: "double", - FriendshipMultiplier.internal_name: "triple", - DebrisMultiplier.internal_name: DebrisMultiplier.option_half, - QuickStart.internal_name: QuickStart.option_true, - Gifting.internal_name: Gifting.option_true, - "death_link": "false", -} - -hard_settings = { - Goal.internal_name: Goal.option_grandpa_evaluation, - FarmType.internal_name: "random", - StartingMoney.internal_name: "extra", - ProfitMargin.internal_name: "normal", - BundleRandomization.internal_name: BundleRandomization.option_remixed, - BundlePrice.internal_name: BundlePrice.option_expensive, - EntranceRandomization.internal_name: EntranceRandomization.option_buildings_without_house, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, - SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, - BuildingProgression.internal_name: BuildingProgression.option_progressive, - FestivalLocations.internal_name: FestivalLocations.option_hard, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi_short, - QuestLocations.internal_name: "lots", - Fishsanity.internal_name: Fishsanity.option_all, - Museumsanity.internal_name: Museumsanity.option_all, - Monstersanity.internal_name: Monstersanity.option_progressive_goals, - Shipsanity.internal_name: Shipsanity.option_crops, - Cooksanity.internal_name: Cooksanity.option_queen_of_sauce, - Chefsanity.internal_name: Chefsanity.option_qos_and_purchases, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_all, - FriendsanityHeartSize.internal_name: 4, - Booksanity.internal_name: Booksanity.option_all, - Walnutsanity.internal_name: Walnutsanity.preset_all, - NumberOfMovementBuffs.internal_name: 4, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.default, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, - TrapItems.internal_name: TrapItems.option_hard, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.option_true, - MultipleDaySleepCost.internal_name: "cheap", - ExperienceMultiplier.internal_name: "vanilla", - FriendshipMultiplier.internal_name: "double", - DebrisMultiplier.internal_name: DebrisMultiplier.option_vanilla, - QuickStart.internal_name: QuickStart.option_true, - Gifting.internal_name: Gifting.option_true, - "death_link": "true", -} - -nightmare_settings = { - Goal.internal_name: Goal.option_community_center, - FarmType.internal_name: "random", - StartingMoney.internal_name: "vanilla", - ProfitMargin.internal_name: "half", - BundleRandomization.internal_name: BundleRandomization.option_shuffled, - BundlePrice.internal_name: BundlePrice.option_very_expensive, - EntranceRandomization.internal_name: EntranceRandomization.option_buildings, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, - SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, - BuildingProgression.internal_name: BuildingProgression.option_progressive, - FestivalLocations.internal_name: FestivalLocations.option_hard, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - QuestLocations.internal_name: "maximum", - Fishsanity.internal_name: Fishsanity.option_special, - Museumsanity.internal_name: Museumsanity.option_all, - Monstersanity.internal_name: Monstersanity.option_split_goals, - Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish, - Cooksanity.internal_name: Cooksanity.option_queen_of_sauce, - Chefsanity.internal_name: Chefsanity.option_qos_and_purchases, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_all_with_marriage, - FriendsanityHeartSize.internal_name: 4, - Booksanity.internal_name: Booksanity.option_all, - Walnutsanity.internal_name: Walnutsanity.preset_all, - NumberOfMovementBuffs.internal_name: 2, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.preset_none, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, - TrapItems.internal_name: TrapItems.option_hell, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.option_true, - MultipleDaySleepCost.internal_name: "expensive", - ExperienceMultiplier.internal_name: "half", - FriendshipMultiplier.internal_name: "vanilla", - DebrisMultiplier.internal_name: DebrisMultiplier.option_vanilla, - QuickStart.internal_name: QuickStart.option_false, - Gifting.internal_name: Gifting.option_true, - "death_link": "true", -} - -short_settings = { - Goal.internal_name: Goal.option_bottom_of_the_mines, - FarmType.internal_name: "random", - StartingMoney.internal_name: "filthy rich", - ProfitMargin.internal_name: "quadruple", - BundleRandomization.internal_name: BundleRandomization.option_remixed, - BundlePrice.internal_name: BundlePrice.option_minimum, - EntranceRandomization.internal_name: EntranceRandomization.option_disabled, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized_not_winter, - Cropsanity.internal_name: Cropsanity.option_disabled, - BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive_very_cheap, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive, - SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, - FestivalLocations.internal_name: FestivalLocations.option_disabled, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_vanilla_very_short, - QuestLocations.internal_name: "none", - Fishsanity.internal_name: Fishsanity.option_none, - Museumsanity.internal_name: Museumsanity.option_none, - Monstersanity.internal_name: Monstersanity.option_none, - Shipsanity.internal_name: Shipsanity.option_none, - Cooksanity.internal_name: Cooksanity.option_none, - Chefsanity.internal_name: Chefsanity.option_none, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_none, - FriendsanityHeartSize.internal_name: 4, - Booksanity.internal_name: Booksanity.option_none, - Walnutsanity.internal_name: Walnutsanity.preset_none, - NumberOfMovementBuffs.internal_name: 10, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.preset_all, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.option_easy, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.option_true, - MultipleDaySleepCost.internal_name: "free", - ExperienceMultiplier.internal_name: "quadruple", - FriendshipMultiplier.internal_name: 800, - DebrisMultiplier.internal_name: DebrisMultiplier.option_none, - QuickStart.internal_name: QuickStart.option_true, - Gifting.internal_name: Gifting.option_true, - "death_link": "false", -} - -minsanity_settings = { - Goal.internal_name: Goal.default, - FarmType.internal_name: "random", - StartingMoney.internal_name: StartingMoney.default, - ProfitMargin.internal_name: ProfitMargin.default, - BundleRandomization.internal_name: BundleRandomization.default, - BundlePrice.internal_name: BundlePrice.default, - EntranceRandomization.internal_name: EntranceRandomization.default, - SeasonRandomization.internal_name: SeasonRandomization.option_disabled, - Cropsanity.internal_name: Cropsanity.option_disabled, - BackpackProgression.internal_name: BackpackProgression.option_vanilla, - ToolProgression.internal_name: ToolProgression.option_vanilla, - ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, - SkillProgression.internal_name: SkillProgression.option_vanilla, - BuildingProgression.internal_name: BuildingProgression.option_vanilla, - FestivalLocations.internal_name: FestivalLocations.option_disabled, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_vanilla_very_short, - QuestLocations.internal_name: "none", - Fishsanity.internal_name: Fishsanity.option_none, - Museumsanity.internal_name: Museumsanity.option_none, - Monstersanity.internal_name: Monstersanity.option_none, - Shipsanity.internal_name: Shipsanity.option_none, - Cooksanity.internal_name: Cooksanity.option_none, - Chefsanity.internal_name: Chefsanity.option_none, - Craftsanity.internal_name: Craftsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_none, - FriendsanityHeartSize.internal_name: FriendsanityHeartSize.default, - Booksanity.internal_name: Booksanity.option_none, - Walnutsanity.internal_name: Walnutsanity.preset_none, - NumberOfMovementBuffs.internal_name: NumberOfMovementBuffs.default, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.default, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.default, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.default, - MultipleDaySleepCost.internal_name: MultipleDaySleepCost.default, - ExperienceMultiplier.internal_name: ExperienceMultiplier.default, - FriendshipMultiplier.internal_name: FriendshipMultiplier.default, - DebrisMultiplier.internal_name: DebrisMultiplier.default, - QuickStart.internal_name: QuickStart.default, - Gifting.internal_name: Gifting.default, - "death_link": DeathLink.default, -} - -allsanity_settings = { - Goal.internal_name: Goal.default, - FarmType.internal_name: "random", - StartingMoney.internal_name: StartingMoney.default, - ProfitMargin.internal_name: ProfitMargin.default, - BundleRandomization.internal_name: BundleRandomization.default, - BundlePrice.internal_name: BundlePrice.default, - EntranceRandomization.internal_name: EntranceRandomization.option_buildings, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive, - SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, - BuildingProgression.internal_name: BuildingProgression.option_progressive, - FestivalLocations.internal_name: FestivalLocations.option_hard, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - QuestLocations.internal_name: "maximum", - Fishsanity.internal_name: Fishsanity.option_all, - Museumsanity.internal_name: Museumsanity.option_all, - Monstersanity.internal_name: Monstersanity.option_progressive_goals, - Shipsanity.internal_name: Shipsanity.option_everything, - Cooksanity.internal_name: Cooksanity.option_all, - Chefsanity.internal_name: Chefsanity.option_all, - Craftsanity.internal_name: Craftsanity.option_all, - Friendsanity.internal_name: Friendsanity.option_all, - FriendsanityHeartSize.internal_name: 1, - Booksanity.internal_name: Booksanity.option_all, - Walnutsanity.internal_name: Walnutsanity.preset_all, - NumberOfMovementBuffs.internal_name: 12, - EnabledFillerBuffs.internal_name: EnabledFillerBuffs.preset_all, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, - TrapItems.internal_name: TrapItems.default, - MultipleDaySleepEnabled.internal_name: MultipleDaySleepEnabled.default, - MultipleDaySleepCost.internal_name: MultipleDaySleepCost.default, - ExperienceMultiplier.internal_name: ExperienceMultiplier.default, - FriendshipMultiplier.internal_name: FriendshipMultiplier.default, - DebrisMultiplier.internal_name: DebrisMultiplier.default, - QuickStart.internal_name: QuickStart.default, - Gifting.internal_name: Gifting.default, - "death_link": DeathLink.default, -} -# @formatter:on - - -sv_options_presets: Dict[str, Dict[str, Any]] = { - "All random": all_random_settings, - "Easy": easy_settings, - "Medium": medium_settings, - "Hard": hard_settings, - "Nightmare": nightmare_settings, - "Short": short_settings, - "Minsanity": minsanity_settings, - "Allsanity": allsanity_settings, -} diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 96f081788041..54afc31eb892 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -25,7 +25,7 @@ from .stardew_rule import And, StardewRule, true_ from .stardew_rule.indirect_connection import look_for_indirect_connection from .stardew_rule.rule_explain import explain -from .strings.ap_names.ap_option_names import OptionName +from .strings.ap_names.ap_option_names import WalnutsanityOptionName from .strings.ap_names.community_upgrade_names import CommunityUpgrade from .strings.ap_names.mods.mod_items import SVEQuestItem, SVERunes from .strings.ap_names.transport_names import Transportation @@ -436,7 +436,7 @@ def set_walnut_rules(logic: StardewLogic, multiworld, player, world_options: Sta def set_walnut_puzzle_rules(logic: StardewLogic, multiworld, player, world_options): - if OptionName.walnutsanity_puzzles not in world_options.walnutsanity: + if WalnutsanityOptionName.puzzles not in world_options.walnutsanity: return MultiWorldRules.add_rule(multiworld.get_location("Open Golden Coconut", player), logic.has(Geode.golden_coconut)) @@ -463,14 +463,14 @@ def set_walnut_puzzle_rules(logic: StardewLogic, multiworld, player, world_optio def set_walnut_bushes_rules(logic, multiworld, player, world_options): - if OptionName.walnutsanity_bushes not in world_options.walnutsanity: + if WalnutsanityOptionName.bushes not in world_options.walnutsanity: return # I don't think any of the bushes require something special, but that might change with ER return def set_walnut_dig_spot_rules(logic, multiworld, player, world_options): - if OptionName.walnutsanity_dig_spots not in world_options.walnutsanity: + if WalnutsanityOptionName.dig_spots not in world_options.walnutsanity: return for dig_spot_walnut in locations.locations_by_tag[LocationTags.WALNUTSANITY_DIG]: @@ -483,7 +483,7 @@ def set_walnut_dig_spot_rules(logic, multiworld, player, world_options): def set_walnut_repeatable_rules(logic, multiworld, player, world_options): - if OptionName.walnutsanity_repeatables not in world_options.walnutsanity: + if WalnutsanityOptionName.repeatables not in world_options.walnutsanity: return for i in range(1, 6): MultiWorldRules.set_rule(multiworld.get_location(f"Fishing Walnut {i}", player), logic.tool.has_fishing_rod(1)) diff --git a/worlds/stardew_valley/strings/ap_names/ap_option_names.py b/worlds/stardew_valley/strings/ap_names/ap_option_names.py index a5cc10f7d7b8..7ff2cc783d11 100644 --- a/worlds/stardew_valley/strings/ap_names/ap_option_names.py +++ b/worlds/stardew_valley/strings/ap_names/ap_option_names.py @@ -1,16 +1,19 @@ -class OptionName: - walnutsanity_puzzles = "Puzzles" - walnutsanity_bushes = "Bushes" - walnutsanity_dig_spots = "Dig Spots" - walnutsanity_repeatables = "Repeatables" - buff_luck = "Luck" - buff_damage = "Damage" - buff_defense = "Defense" - buff_immunity = "Immunity" - buff_health = "Health" - buff_energy = "Energy" - buff_bite = "Bite Rate" - buff_fish_trap = "Fish Trap" - buff_fishing_bar = "Fishing Bar Size" - buff_quality = "Quality" - buff_glow = "Glow" +class WalnutsanityOptionName: + puzzles = "Puzzles" + bushes = "Bushes" + dig_spots = "Dig Spots" + repeatables = "Repeatables" + + +class BuffOptionName: + luck = "Luck" + damage = "Damage" + defense = "Defense" + immunity = "Immunity" + health = "Health" + energy = "Energy" + bite = "Bite Rate" + fish_trap = "Fish Trap" + fishing_bar = "Fishing Bar Size" + quality = "Quality" + glow = "Glow" diff --git a/worlds/stardew_valley/strings/ap_names/mods/__init__.py b/worlds/stardew_valley/strings/ap_names/mods/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/test/TestBooksanity.py b/worlds/stardew_valley/test/TestBooksanity.py index 3ca52f5728c1..942f35d961a9 100644 --- a/worlds/stardew_valley/test/TestBooksanity.py +++ b/worlds/stardew_valley/test/TestBooksanity.py @@ -1,6 +1,5 @@ from . import SVTestBase from ..options import ExcludeGingerIsland, Booksanity, Shipsanity -from ..strings.ap_names.ap_option_names import OptionName from ..strings.book_names import Book, LostBook power_books = [Book.animal_catalogue, Book.book_of_mysteries, diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 9db7f06ff5a5..2cd83f013ae5 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -1,6 +1,6 @@ import itertools -from Options import NamedRange, Accessibility +from Options import NamedRange from . import SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld from .assertion import WorldAssertMixin from .long.option_names import all_option_choices @@ -54,23 +54,6 @@ def test_given_goal_when_generate_then_victory_is_in_correct_location(self): victory = multi_world.find_item("Victory", 1) self.assertEqual(victory.name, location) - def test_given_perfection_goal_when_generate_then_accessibility_is_forced_to_full(self): - """There is a bug with the current victory condition of the perfection goal that can create unwinnable seeds if the accessibility is set to minimal and - the world gets flooded with progression items through plando. This will increase the amount of collected progression items pass the total amount - calculated for the world when creating the item pool. This will cause the victory condition to be met before all locations are collected, so some could - be left inaccessible, which in practice will make the seed unwinnable. - """ - for accessibility in Accessibility.options.keys(): - world_options = {Goal.internal_name: Goal.option_perfection, "accessibility": accessibility} - with self.solo_world_sub_test(f"Accessibility: {accessibility}", world_options) as (_, world): - self.assertEqual(world.options.accessibility, Accessibility.option_full) - - def test_given_allsanity_goal_when_generate_then_accessibility_is_forced_to_full(self): - for accessibility in Accessibility.options.keys(): - world_options = {Goal.internal_name: Goal.option_allsanity, "accessibility": accessibility} - with self.solo_world_sub_test(f"Accessibility: {accessibility}", world_options) as (_, world): - self.assertEqual(world.options.accessibility, Accessibility.option_full) - class TestSeasonRandomization(SVTestCase): def test_given_disabled_when_generate_then_all_seasons_are_precollected(self): @@ -144,7 +127,7 @@ def test_given_progressive_when_generate_then_tool_upgrades_are_locations(self): class TestGenerateAllOptionsWithExcludeGingerIsland(WorldAssertMixin, SVTestCase): - def test_given_choice_when_generate_exclude_ginger_island(self): + def test_given_choice_when_generate_exclude_ginger_island_then_ginger_island_is_properly_excluded(self): for option, option_choice in all_option_choices: if option is ExcludeGingerIsland: continue @@ -163,19 +146,6 @@ def test_given_choice_when_generate_exclude_ginger_island(self): self.assert_basic_checks(multiworld) self.assert_no_ginger_island_content(multiworld) - def test_given_island_related_goal_then_override_exclude_ginger_island(self): - island_goals = ["greatest_walnut_hunter", "perfection"] - for goal, exclude_island in itertools.product(island_goals, ExcludeGingerIsland.options): - world_options = { - Goal: goal, - ExcludeGingerIsland: exclude_island - } - - with self.solo_world_sub_test(f"Goal: {goal}, {ExcludeGingerIsland.internal_name}: {exclude_island}", world_options) \ - as (multiworld, stardew_world): - self.assertEqual(stardew_world.options.exclude_ginger_island, ExcludeGingerIsland.option_false) - self.assert_basic_checks(multiworld) - class TestTraps(SVTestCase): def test_given_no_traps_when_generate_then_no_trap_in_pool(self): diff --git a/worlds/stardew_valley/test/TestOptionsPairs.py b/worlds/stardew_valley/test/TestOptionsPairs.py index d953696e887d..d489ab1ff282 100644 --- a/worlds/stardew_valley/test/TestOptionsPairs.py +++ b/worlds/stardew_valley/test/TestOptionsPairs.py @@ -1,13 +1,12 @@ from . import SVTestBase from .assertion import WorldAssertMixin from .. import options -from ..options import Goal, QuestLocations class TestCrypticNoteNoQuests(WorldAssertMixin, SVTestBase): options = { - Goal.internal_name: Goal.option_cryptic_note, - QuestLocations.internal_name: "none" + options.Goal.internal_name: options.Goal.option_cryptic_note, + options.QuestLocations.internal_name: "none" } def test_given_option_pair_then_basic_checks(self): @@ -16,8 +15,8 @@ def test_given_option_pair_then_basic_checks(self): class TestCompleteCollectionNoQuests(WorldAssertMixin, SVTestBase): options = { - Goal.internal_name: Goal.option_complete_collection, - QuestLocations.internal_name: "none" + options.Goal.internal_name: options.Goal.option_complete_collection, + options.QuestLocations.internal_name: "none" } def test_given_option_pair_then_basic_checks(self): @@ -26,8 +25,8 @@ def test_given_option_pair_then_basic_checks(self): class TestProtectorOfTheValleyNoQuests(WorldAssertMixin, SVTestBase): options = { - Goal.internal_name: Goal.option_protector_of_the_valley, - QuestLocations.internal_name: "none" + options.Goal.internal_name: options.Goal.option_protector_of_the_valley, + options.QuestLocations.internal_name: "none" } def test_given_option_pair_then_basic_checks(self): @@ -36,8 +35,8 @@ def test_given_option_pair_then_basic_checks(self): class TestCraftMasterNoQuests(WorldAssertMixin, SVTestBase): options = { - Goal.internal_name: Goal.option_craft_master, - QuestLocations.internal_name: "none" + options.Goal.internal_name: options.Goal.option_craft_master, + options.QuestLocations.internal_name: "none" } def test_given_option_pair_then_basic_checks(self): @@ -46,7 +45,7 @@ def test_given_option_pair_then_basic_checks(self): class TestCraftMasterNoSpecialOrder(WorldAssertMixin, SVTestBase): options = { - options.Goal.internal_name: Goal.option_craft_master, + options.Goal.internal_name: options.Goal.option_craft_master, options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.alias_disabled, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, options.Craftsanity.internal_name: options.Craftsanity.option_none diff --git a/worlds/stardew_valley/test/TestRegions.py b/worlds/stardew_valley/test/TestRegions.py index c2e962d88a7e..bd1b67297473 100644 --- a/worlds/stardew_valley/test/TestRegions.py +++ b/worlds/stardew_valley/test/TestRegions.py @@ -3,7 +3,8 @@ from typing import Set from BaseClasses import get_seed -from . import SVTestCase, complete_options_with_default +from . import SVTestCase +from .options.utils import fill_dataclass_with_default from .. import create_content from ..options import EntranceRandomization, ExcludeGingerIsland, SkillProgression from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag, create_final_connections_and_regions @@ -59,7 +60,7 @@ def test_entrance_randomization(self): (EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), (EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS), (EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: - sv_options = complete_options_with_default({ + sv_options = fill_dataclass_with_default({ EntranceRandomization.internal_name: option, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, @@ -87,7 +88,7 @@ def test_entrance_randomization_without_island(self): (EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS), (EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: - sv_options = complete_options_with_default({ + sv_options = fill_dataclass_with_default({ EntranceRandomization.internal_name: option, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, @@ -116,7 +117,7 @@ def test_entrance_randomization_without_island(self): f"Connections are duplicated in randomization.") def test_cannot_put_island_access_on_island(self): - sv_options = complete_options_with_default({ + sv_options = fill_dataclass_with_default({ EntranceRandomization.internal_name: EntranceRandomization.option_buildings, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, diff --git a/worlds/stardew_valley/test/TestWalnutsanity.py b/worlds/stardew_valley/test/TestWalnutsanity.py index e1ab348def41..c1e8c2c8f095 100644 --- a/worlds/stardew_valley/test/TestWalnutsanity.py +++ b/worlds/stardew_valley/test/TestWalnutsanity.py @@ -1,6 +1,6 @@ from . import SVTestBase from ..options import ExcludeGingerIsland, Walnutsanity -from ..strings.ap_names.ap_option_names import OptionName +from ..strings.ap_names.ap_option_names import WalnutsanityOptionName class TestWalnutsanityNone(SVTestBase): @@ -49,7 +49,7 @@ def test_logic_received_walnuts(self): class TestWalnutsanityPuzzles(SVTestBase): options = { ExcludeGingerIsland: ExcludeGingerIsland.option_false, - Walnutsanity: frozenset({OptionName.walnutsanity_puzzles}), + Walnutsanity: frozenset({WalnutsanityOptionName.puzzles}), } def test_only_puzzle_walnut_locations(self): @@ -90,7 +90,7 @@ def test_field_office_locations_require_professor_snail(self): class TestWalnutsanityBushes(SVTestBase): options = { ExcludeGingerIsland: ExcludeGingerIsland.option_false, - Walnutsanity: frozenset({OptionName.walnutsanity_bushes}), + Walnutsanity: frozenset({WalnutsanityOptionName.bushes}), } def test_only_bush_walnut_locations(self): @@ -108,7 +108,7 @@ def test_only_bush_walnut_locations(self): class TestWalnutsanityPuzzlesAndBushes(SVTestBase): options = { ExcludeGingerIsland: ExcludeGingerIsland.option_false, - Walnutsanity: frozenset({OptionName.walnutsanity_puzzles, OptionName.walnutsanity_bushes}), + Walnutsanity: frozenset({WalnutsanityOptionName.puzzles, WalnutsanityOptionName.bushes}), } def test_only_bush_walnut_locations(self): @@ -136,7 +136,7 @@ def test_logic_received_walnuts(self): class TestWalnutsanityDigSpots(SVTestBase): options = { ExcludeGingerIsland: ExcludeGingerIsland.option_false, - Walnutsanity: frozenset({OptionName.walnutsanity_dig_spots}), + Walnutsanity: frozenset({WalnutsanityOptionName.dig_spots}), } def test_only_dig_spots_walnut_locations(self): @@ -154,7 +154,7 @@ def test_only_dig_spots_walnut_locations(self): class TestWalnutsanityRepeatables(SVTestBase): options = { ExcludeGingerIsland: ExcludeGingerIsland.option_false, - Walnutsanity: frozenset({OptionName.walnutsanity_repeatables}), + Walnutsanity: frozenset({WalnutsanityOptionName.repeatables}), } def test_only_repeatable_walnut_locations(self): diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 1a312e569d11..de0ed97882e3 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -2,18 +2,17 @@ import os import threading import unittest -from argparse import Namespace from contextlib import contextmanager from typing import Dict, ClassVar, Iterable, Tuple, Optional, List, Union, Any -from BaseClasses import MultiWorld, CollectionState, PlandoOptions, get_seed, Location, Item -from Options import VerifyKeys +from BaseClasses import MultiWorld, CollectionState, get_seed, Location, Item from test.bases import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld from worlds.AutoWorld import call_all from .assertion import RuleAssertMixin +from .options.utils import fill_namespace_with_default, parse_class_option_keys, fill_dataclass_with_default from .. import StardewValleyWorld, options, StardewItem -from ..options import StardewValleyOptions, StardewValleyOption +from ..options import StardewValleyOption logger = logging.getLogger(__name__) @@ -360,15 +359,7 @@ def setup_solo_multiworld(test_options: Optional[Dict[Union[str, StardewValleyOp multiworld = setup_base_solo_multiworld(StardewValleyWorld, (), seed=seed) # print(f"Seed: {multiworld.seed}") # Uncomment to print the seed for every test - args = Namespace() - for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): - value = option.from_any(test_options.get(name, option.default)) - - if issubclass(option, VerifyKeys): - # Values should already be verified, but just in case... - value.verify(StardewValleyWorld, "Tester", PlandoOptions.bosses) - - setattr(args, name, {1: value}) + args = fill_namespace_with_default(test_options) multiworld.set_options(args) if "start_inventory" in test_options: @@ -388,24 +379,6 @@ def setup_solo_multiworld(test_options: Optional[Dict[Union[str, StardewValleyOp return multiworld -def parse_class_option_keys(test_options: Optional[Dict]) -> dict: - """ Now the option class is allowed as key. """ - if test_options is None: - return {} - parsed_options = {} - - for option, value in test_options.items(): - if hasattr(option, "internal_name"): - assert option.internal_name not in test_options, "Defined two times by class and internal_name" - parsed_options[option.internal_name] = value - else: - assert option in StardewValleyOptions.type_hints, \ - f"All keys of world_options must be a possible Stardew Valley option, {option} is not." - parsed_options[option] = value - - return parsed_options - - def search_world_cache(cache: Dict[frozenset, MultiWorld], frozen_options: frozenset) -> Optional[MultiWorld]: try: return cache[frozen_options] @@ -421,16 +394,6 @@ def add_to_world_cache(cache: Dict[frozenset, MultiWorld], frozen_options: froze cache[frozen_options] = multi_world -def complete_options_with_default(options_to_complete=None) -> StardewValleyOptions: - if options_to_complete is None: - options_to_complete = {} - - for name, option in StardewValleyOptions.type_hints.items(): - options_to_complete[name] = option.from_any(options_to_complete.get(name, option.default)) - - return StardewValleyOptions(**options_to_complete) - - def setup_multiworld(test_options: Iterable[Dict[str, int]] = None, seed=None) -> MultiWorld: # noqa if test_options is None: test_options = [] @@ -442,22 +405,10 @@ def setup_multiworld(test_options: Iterable[Dict[str, int]] = None, seed=None) - for i in range(1, len(test_options) + 1): multiworld.game[i] = StardewValleyWorld.game multiworld.player_name.update({i: f"Tester{i}"}) - args = create_args(test_options) + args = fill_namespace_with_default(test_options) multiworld.set_options(args) for step in gen_steps: call_all(multiworld, step) return multiworld - - -def create_args(test_options): - args = Namespace() - for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): - options = {} - for i in range(1, len(test_options) + 1): - player_options = test_options[i - 1] - value = option(player_options[name]) if name in player_options else option.from_any(option.default) - options.update({i: value}) - setattr(args, name, options) - return args diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 56138cf582a7..89f82870e4a7 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,7 +1,8 @@ import random from BaseClasses import get_seed -from .. import SVTestBase, SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, complete_options_with_default, solo_multiworld +from .. import SVTestBase, SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld, \ + fill_dataclass_with_default from ..assertion import ModAssertMixin, WorldAssertMixin from ... import items, Group, ItemClassification, create_content from ... import options @@ -122,7 +123,7 @@ def test_mod_entrance_randomization(self): (options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), (options.EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS), (options.EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: - sv_options = complete_options_with_default({ + sv_options = fill_dataclass_with_default({ options.EntranceRandomization.internal_name: option, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false, SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries, diff --git a/worlds/stardew_valley/test/options/TestForcedOptions.py b/worlds/stardew_valley/test/options/TestForcedOptions.py new file mode 100644 index 000000000000..4c8f0f42c389 --- /dev/null +++ b/worlds/stardew_valley/test/options/TestForcedOptions.py @@ -0,0 +1,84 @@ +import itertools +import unittest + +import Options as ap_options +from .utils import fill_dataclass_with_default +from ... import options +from ...options.forced_options import force_change_options_if_incompatible + + +class TestGoalsRequiringAllLocationsOverrideAccessibility(unittest.TestCase): + + def test_given_goal_requiring_all_locations_when_generate_then_accessibility_is_forced_to_full(self): + """There is a bug with the current victory condition of the perfection goal that can create unwinnable seeds if the accessibility is set to minimal and + the world gets flooded with progression items through plando. This will increase the amount of collected progression items pass the total amount + calculated for the world when creating the item pool. This will cause the victory condition to be met before all locations are collected, so some could + be left inaccessible, which in practice will make the seed unwinnable. + """ + + for goal in [options.Goal.option_perfection, options.Goal.option_allsanity]: + for accessibility in ap_options.Accessibility.options.keys(): + with self.subTest(f"Goal: {options.Goal.get_option_name(goal)} Accessibility: {accessibility}"): + world_options = fill_dataclass_with_default({ + options.Goal: goal, + "accessibility": accessibility + }) + + force_change_options_if_incompatible(world_options, 1, "Tester") + + self.assertEqual(world_options.accessibility.value, ap_options.Accessibility.option_full) + + +class TestGingerIslandRelatedGoalsOverrideGingerIslandExclusion(unittest.TestCase): + + def test_given_island_related_goal_when_generate_then_override_exclude_ginger_island(self): + for goal in [options.Goal.option_greatest_walnut_hunter, options.Goal.option_perfection]: + for exclude_island in options.ExcludeGingerIsland.options: + with self.subTest(f"Goal: {options.Goal.get_option_name(goal)} Exclude Ginger Island: {exclude_island}"): + world_options = fill_dataclass_with_default({ + options.Goal: goal, + options.ExcludeGingerIsland: exclude_island + }) + + force_change_options_if_incompatible(world_options, 1, "Tester") + + self.assertEqual(world_options.exclude_ginger_island.value, options.ExcludeGingerIsland.option_false) + + +class TestGingerIslandExclusionOverridesWalnutsanity(unittest.TestCase): + + def test_given_ginger_island_excluded_when_generate_then_walnutsanity_is_forced_disabled(self): + walnutsanity_options = options.Walnutsanity.valid_keys + for walnutsanity in ( + walnutsanity + for r in range(len(walnutsanity_options) + 1) + for walnutsanity in itertools.combinations(walnutsanity_options, r) + ): + with self.subTest(f"Walnutsanity: {walnutsanity}"): + world_options = fill_dataclass_with_default({ + options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_true, + options.Walnutsanity: walnutsanity + }) + + force_change_options_if_incompatible(world_options, 1, "Tester") + + self.assertEqual(world_options.walnutsanity.value, options.Walnutsanity.preset_none) + + def test_given_ginger_island_related_goal_and_ginger_island_excluded_when_generate_then_walnutsanity_is_not_changed(self): + for goal in [options.Goal.option_greatest_walnut_hunter, options.Goal.option_perfection]: + walnutsanity_options = options.Walnutsanity.valid_keys + for original_walnutsanity_choice in ( + set(walnutsanity) + for r in range(len(walnutsanity_options) + 1) + for walnutsanity in itertools.combinations(walnutsanity_options, r) + ): + with self.subTest(f"Goal: {options.Goal.get_option_name(goal)} Walnutsanity: {original_walnutsanity_choice}"): + world_options = fill_dataclass_with_default({ + options.Goal: goal, + options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_true, + options.Walnutsanity: original_walnutsanity_choice + }) + + force_change_options_if_incompatible(world_options, 1, "Tester") + + self.assertEqual(world_options.walnutsanity.value, original_walnutsanity_choice) diff --git a/worlds/stardew_valley/test/TestPresets.py b/worlds/stardew_valley/test/options/TestPresets.py similarity index 86% rename from worlds/stardew_valley/test/TestPresets.py rename to worlds/stardew_valley/test/options/TestPresets.py index 2bb1c7fbaeaf..9384acd77060 100644 --- a/worlds/stardew_valley/test/TestPresets.py +++ b/worlds/stardew_valley/test/options/TestPresets.py @@ -1,9 +1,7 @@ -import builtins -import inspect - from Options import PerGameCommonOptions, OptionSet -from . import SVTestCase -from .. import sv_options_presets, StardewValleyOptions +from .. import SVTestCase +from ...options import StardewValleyOptions +from ...options.presets import sv_options_presets class TestPresets(SVTestCase): @@ -18,4 +16,4 @@ def test_all_presets_explicitly_set_all_options(self): with self.subTest(f"{preset_name}"): for option_name in mandatory_option_names: with self.subTest(f"{preset_name} -> {option_name}"): - self.assertIn(option_name, sv_options_presets[preset_name]) \ No newline at end of file + self.assertIn(option_name, sv_options_presets[preset_name]) diff --git a/worlds/stardew_valley/test/options/__init__.py b/worlds/stardew_valley/test/options/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/test/options/utils.py b/worlds/stardew_valley/test/options/utils.py new file mode 100644 index 000000000000..9f02105da84f --- /dev/null +++ b/worlds/stardew_valley/test/options/utils.py @@ -0,0 +1,68 @@ +from argparse import Namespace +from typing import Any, Iterable + +from BaseClasses import PlandoOptions +from Options import VerifyKeys +from ... import StardewValleyWorld +from ...options import StardewValleyOptions, StardewValleyOption + + +def parse_class_option_keys(test_options: dict[str | StardewValleyOption, Any] | None) -> dict: + """ Now the option class is allowed as key. """ + if test_options is None: + return {} + parsed_options = {} + + for option, value in test_options.items(): + if hasattr(option, "internal_name"): + assert option.internal_name not in test_options, "Defined two times by class and internal_name" + parsed_options[option.internal_name] = value + else: + assert option in StardewValleyOptions.type_hints, \ + f"All keys of world_options must be a possible Stardew Valley option, {option} is not." + parsed_options[option] = value + + return parsed_options + + +def fill_dataclass_with_default(test_options: dict[str | StardewValleyOption, Any] | None) -> StardewValleyOptions: + test_options = parse_class_option_keys(test_options) + + filled_options = {} + for option_name, option_class in StardewValleyOptions.type_hints.items(): + + value = option_class.from_any(test_options.get(option_name, option_class.default)) + + if issubclass(option_class, VerifyKeys): + # Values should already be verified, but just in case... + value.verify(StardewValleyWorld, "Tester", PlandoOptions.bosses) + + filled_options[option_name] = value + + return StardewValleyOptions(**filled_options) + + +def fill_namespace_with_default(test_options: dict[str, Any] | Iterable[dict[str, Any]]) -> Namespace: + if isinstance(test_options, dict): + test_options = [test_options] + + args = Namespace() + for option_name, option_class in StardewValleyOptions.type_hints.items(): + all_players_option = {} + + for player_id, player_options in enumerate(test_options): + # Player id starts at 1 + player_id += 1 + player_name = f"Tester{player_id}" + + value = option_class.from_any(player_options.get(option_name, option_class.default)) + + if issubclass(option_class, VerifyKeys): + # Values should already be verified, but just in case... + value.verify(StardewValleyWorld, player_name, PlandoOptions.bosses) + + all_players_option[player_id] = value + + setattr(args, option_name, all_players_option) + + return args diff --git a/worlds/stardew_valley/test/stability/TestUniversalTracker.py b/worlds/stardew_valley/test/stability/TestUniversalTracker.py index 3e334098341d..4655b37adf07 100644 --- a/worlds/stardew_valley/test/stability/TestUniversalTracker.py +++ b/worlds/stardew_valley/test/stability/TestUniversalTracker.py @@ -1,7 +1,7 @@ import unittest from unittest.mock import Mock -from .. import SVTestBase, create_args, allsanity_mods_6_x_x +from .. import SVTestBase, allsanity_mods_6_x_x, fill_namespace_with_default from ... import STARDEW_VALLEY, FarmType, BundleRandomization, EntranceRandomization @@ -29,7 +29,7 @@ def test_all_locations_and_items_are_the_same_between_two_generations(self): fake_context = Mock() fake_context.re_gen_passthrough = {STARDEW_VALLEY: ut_data} - args = create_args({0: self.options}) + args = fill_namespace_with_default({0: self.options}) args.outputpath = None args.outputname = None args.multi = 1