diff --git a/Mystery.py b/Mystery.py index e4565666..5632ef0c 100644 --- a/Mystery.py +++ b/Mystery.py @@ -291,31 +291,52 @@ def roll_percentage(percentage: typing.Union[int, float]) -> bool: percentage is expected to be in range [0, 100]""" return random.random() < (float(percentage) / 100) +def roll_linked_options(weights: dict) -> dict: + weights = weights.copy() # make sure we don't write back to other weights sets in same_settings + for option_set in weights["linked_options"]: + if "name" not in option_set: + raise ValueError("One of your linked options does not have a name.") + try: + if roll_percentage(option_set["percentage"]): + logging.debug(f"Linked option {option_set['name']} triggered.") + logging.debug(f'Applying {option_set["options"]}') + new_options = set(option_set["options"]) - set(weights) + weights.update(option_set["options"]) + if new_options: + for new_option in new_options: + logging.warning(f'Linked Suboption "{new_option}" of "{option_set["name"]}" did not ' + f'overwrite a root option. ' + f"This is probably in error.") + else: + logging.debug(f"linked option {option_set['name']} skipped.") + except Exception as e: + raise ValueError(f"Linked option {option_set['name']} is destroyed. " + f"Please fix your linked option.") from e + return weights -def roll_settings(weights, plando_options: typing.Set[str] = frozenset(("bosses"))): - ret = argparse.Namespace() +def roll_triggers(weights: dict) -> dict: + weights = weights.copy() # make sure we don't write back to other weights sets in same_settings + for option_set in weights["triggers"]: + try: + key = get_choice("option_name", option_set) + trigger_result = get_choice("option_result", option_set) + result = get_choice(key, weights) + if result == trigger_result and roll_percentage(get_choice("percentage", option_set, 100)): + weights.update(option_set["options"]) + weights[key] = result + except Exception as e: + raise ValueError(f"A trigger is destroyed. " + f"Please fix your triggers.") from e + return weights + +def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("bosses"))): if "linked_options" in weights: - weights = weights.copy() # make sure we don't write back to other weights sets in same_settings - for option_set in weights["linked_options"]: - if "name" not in option_set: - raise ValueError("One of your linked options does not have a name.") - try: - if roll_percentage(option_set["percentage"]): - logging.debug(f"Linked option {option_set['name']} triggered.") - logging.debug(f'Applying {option_set["options"]}') - new_options = set(option_set["options"]) - set(weights) - weights.update(option_set["options"]) - if new_options: - for new_option in new_options: - logging.warning(f'Linked Suboption "{new_option}" of "{option_set["name"]}" did not ' - f'overwrite a root option. ' - f"This is probably in error.") - else: - logging.debug(f"linked option {option_set['name']} skipped.") - except Exception as e: - raise ValueError(f"Linked option {option_set['name']} is destroyed. " - f"Please fix your linked option.") from e + weights = roll_linked_options(weights) + if "triggers" in weights: + weights = roll_triggers(weights) + + ret = argparse.Namespace() ret.name = get_choice('name', weights) if ret.name: ret.name = handle_name(ret.name) diff --git a/playerSettings.yaml b/playerSettings.yaml index 14e9248f..22861dc2 100644 --- a/playerSettings.yaml +++ b/playerSettings.yaml @@ -97,9 +97,9 @@ goals: ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon local_ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon ice_rod_hunt: 0 # You start with everything needed to 216 the seed. Find the Ice rod, then kill Trinexx at Turtle rock. -pyramid_open: +open_pyramid: goal: 50 # Opens the pyramid if the goal requires you to kill Ganon, unless the goal is Slow Ganon or All Dungeons - auto: 0 # Same as Goal, but also opens when any non-dungeon entrance shuffle is used + auto: 0 # Same as Goal, but also is closed if holes are shuffled and ganon is part of the shuffle pool yes: 0 # Pyramid hole is always open. Ganon's vulnerable condition is still required before he can he hurt no: 0 # Pyramid hole is always closed until you defeat Agahnim atop Ganon's Tower triforce_pieces_mode: #Determine how to calculate the extra available triforce pieces. @@ -322,6 +322,13 @@ linked_options: hard: 1 expert: 1 percentage: 0 # Set this to the percentage chance you want enemizer +# triggers that replace options upon rolling certain options +triggers: + - option_name: enemy_damage # targets enemy_damage + option_result: shuffled # if it rolls shuffled + percentage: 0 # AND has a 0 percent chance (meaning this is default disabled, just to show how it works) + options: # then inserts these options + swords: assured ### door rando only options ### door_shuffle: # Only available if the host uses the doors branch, it is ignored otherwise vanilla: 50 # Everything should be like in vanilla