Timespinner: Make RisingTidesOverrides consistent with normal yaml behaviour. (#1474)

* Make RisingTidesOverrides consistent with normal yaml behaviour.

* Each of the options can be either string directly specifying the option, or dictionary.
* If dictionary, ensure that at least one of the options is greater than zero.

* Made keys optional

* A lot less copy/pasta.

---------

Co-authored-by: Jarno Westhof <jarnowesthof@gmail.com>
This commit is contained in:
CaitSith2 2023-02-22 17:11:27 -08:00 committed by GitHub
parent 0eb66957b1
commit cb3d40624c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 45 deletions

View File

@ -1,7 +1,7 @@
from typing import Dict, Union, List from typing import Dict, Union, List
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, Option, OptionDict, OptionList from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, Option, OptionDict, OptionList
from schema import Schema, And, Optional from schema import Schema, And, Optional, Or
class StartWithJewelryBox(Toggle): class StartWithJewelryBox(Toggle):
@ -308,47 +308,44 @@ class RisingTides(Toggle):
display_name = "Rising Tides" display_name = "Rising Tides"
def rising_tide_option(location: str, with_save_point_option: bool = False) -> Dict[Optional, Or]:
if with_save_point_option:
return {
Optional(location): Or(
And({
Optional("Dry"): And(int, lambda n: n >= 0),
Optional("Flooded"): And(int, lambda n: n >= 0),
Optional("FloodedWithSavePointAvailable"): And(int, lambda n: n >= 0)
}, lambda d: any(v > 0 for v in d.values())),
"Dry",
"Flooded",
"FloodedWithSavePointAvailable")
}
else:
return {
Optional(location): Or(
And({
Optional("Dry"): And(int, lambda n: n >= 0),
Optional("Flooded"): And(int, lambda n: n >= 0)
}, lambda d: any(v > 0 for v in d.values())),
"Dry",
"Flooded")
}
class RisingTidesOverrides(OptionDict): class RisingTidesOverrides(OptionDict):
"""Odds for specific areas to be flooded or drained, only has effect when RisingTides is on. """Odds for specific areas to be flooded or drained, only has effect when RisingTides is on.
Areas that are not specified will roll with the default 33% chance of getting flooded or drained""" Areas that are not specified will roll with the default 33% chance of getting flooded or drained"""
schema = Schema({ schema = Schema({
Optional("Xarion"): { **rising_tide_option("Xarion"),
"Dry": And(int, lambda n: n >= 0), **rising_tide_option("Maw"),
"Flooded": And(int, lambda n: n >= 0) **rising_tide_option("AncientPyramidShaft"),
}, **rising_tide_option("Sandman"),
Optional("Maw"): { **rising_tide_option("CastleMoat"),
"Dry": And(int, lambda n: n >= 0), **rising_tide_option("CastleBasement", with_save_point_option=True),
"Flooded": And(int, lambda n: n >= 0) **rising_tide_option("CastleCourtyard"),
}, **rising_tide_option("LakeDesolation"),
Optional("AncientPyramidShaft"): { **rising_tide_option("LakeSerene")
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("Sandman"): {
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("CastleMoat"): {
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("CastleBasement"): {
"Dry": And(int, lambda n: n >= 0),
"FloodedWithSavePointAvailable": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("CastleCourtyard"): {
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("LakeDesolation"): {
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
},
Optional("LakeSerene"): {
"Dry": And(int, lambda n: n >= 0),
"Flooded": And(int, lambda n: n >= 0)
}
}) })
display_name = "Rising Tides Overrides" display_name = "Rising Tides Overrides"
default = { default = {

View File

@ -21,7 +21,7 @@ class PreCalculatedWeights:
dry_lake_serene: bool dry_lake_serene: bool
def __init__(self, world: MultiWorld, player: int): def __init__(self, world: MultiWorld, player: int):
weights_overrrides: Dict[str, Dict[str, int]] = self.get_flood_weights_overrides(world, player) weights_overrrides: Dict[str, Union[str, Dict[str, int]]] = self.get_flood_weights_overrides(world, player)
self.flood_basement, self.flood_basement_high = \ self.flood_basement, self.flood_basement_high = \
self.roll_flood_setting_with_available_save(world, player, weights_overrrides, "CastleBasement") self.roll_flood_setting_with_available_save(world, player, weights_overrrides, "CastleBasement")
@ -87,8 +87,8 @@ class PreCalculatedWeights:
) )
@staticmethod @staticmethod
def get_flood_weights_overrides( world: MultiWorld, player: int) -> Dict[str, int]: def get_flood_weights_overrides( world: MultiWorld, player: int) -> Dict[str, Union[str, Dict[str, int]]]:
weights_overrides_option: Union[int, Dict[str, Dict[str, int]]] = \ weights_overrides_option: Union[int, Dict[str, Union[str, Dict[str, int]]]] = \
get_option_value(world, player, "RisingTidesOverrides") get_option_value(world, player, "RisingTidesOverrides")
if weights_overrides_option == 0: if weights_overrides_option == 0:
@ -97,26 +97,32 @@ class PreCalculatedWeights:
return weights_overrides_option return weights_overrides_option
@staticmethod @staticmethod
def roll_flood_setting(world: MultiWorld, player: int, weights: Dict[str, Dict[str, int]], key: str) -> bool: def roll_flood_setting(world: MultiWorld, player: int, weights: Dict[str, Union[Dict[str, int], str]], key: str) -> bool:
if not world or not is_option_enabled(world, player, "RisingTides"): if not world or not is_option_enabled(world, player, "RisingTides"):
return False return False
weights = weights[key] if key in weights else { "Dry": 67, "Flooded": 33 } weights = weights[key] if key in weights else { "Dry": 67, "Flooded": 33 }
if isinstance(weights, dict):
result: str = world.random.choices(list(weights.keys()), weights=list(map(int, weights.values())))[0] result: str = world.random.choices(list(weights.keys()), weights=list(map(int, weights.values())))[0]
else:
result: str = weights
return result == "Flooded" return result == "Flooded"
@staticmethod @staticmethod
def roll_flood_setting_with_available_save(world: MultiWorld, player: int, def roll_flood_setting_with_available_save(world: MultiWorld, player: int,
weights: Dict[str, Dict[str, int]], key: str) -> Tuple[bool, bool]: weights: Dict[str, Union[Dict[str, int], str]], key: str) -> Tuple[bool, bool]:
if not world or not is_option_enabled(world, player, "RisingTides"): if not world or not is_option_enabled(world, player, "RisingTides"):
return False, False return False, False
weights = weights[key] if key in weights else {"Dry": 66, "Flooded": 17, "FloodedWithSavePointAvailable": 17} weights = weights[key] if key in weights else {"Dry": 66, "Flooded": 17, "FloodedWithSavePointAvailable": 17}
if isinstance(weights, dict):
result: str = world.random.choices(list(weights.keys()), weights=list(map(int, weights.values())))[0] result: str = world.random.choices(list(weights.keys()), weights=list(map(int, weights.values())))[0]
else:
result: str = weights
if result == "Dry": if result == "Dry":
return False, False return False, False