From 7678cb0c0cf2abe0b0ae932603a065bd3e84a945 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 26 Mar 2024 14:37:04 +0100 Subject: [PATCH 1/6] Core: remove now unused stuff in Generate.py --- Generate.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Generate.py b/Generate.py index 56979334b547..1166ee0ce62e 100644 --- a/Generate.py +++ b/Generate.py @@ -21,7 +21,6 @@ from Main import main as ERmain from settings import get_settings from Utils import parse_yamls, version_tuple, __version__, tuplize_version -from worlds.alttp import Options as LttPOptions from worlds.alttp.EntranceRandomizer import parse_arguments from worlds.alttp.Text import TextTable from worlds.AutoWorld import AutoWorldRegister @@ -310,13 +309,6 @@ def handle_name(name: str, player: int, name_counter: Counter): return new_name -def prefer_int(input_data: str) -> Union[str, int]: - try: - return int(input_data) - except: - return input_data - - def roll_percentage(percentage: Union[int, float]) -> bool: """Roll a percentage chance. percentage is expected to be in range [0, 100]""" From b8f78cb9a6e8754230fe274b611a7f0de9cb02fe Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 26 Mar 2024 14:45:46 +0100 Subject: [PATCH 2/6] Generate: introduce Remove, similar to Merge --- Generate.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Generate.py b/Generate.py index 1166ee0ce62e..7c7130e5d818 100644 --- a/Generate.py +++ b/Generate.py @@ -9,6 +9,7 @@ import urllib.request from collections import Counter from typing import Any, Dict, Tuple, Union +from itertools import cycle import ModuleUpdate @@ -319,7 +320,7 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str logging.debug(f'Applying {new_weights}') cleaned_weights = {} for option in new_weights: - option_name = option.lstrip("+") + option_name = option.lstrip("+-") if option.startswith("+") and option_name in weights: cleaned_value = weights[option_name] new_value = new_weights[option] @@ -331,6 +332,20 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str raise Exception(f"Cannot apply merge to non-dict, set, or list type {option_name}," f" received {type(new_value).__name__}.") cleaned_weights[option_name] = cleaned_value + elif option.startswith("-") and option_name in weights: + cleaned_value = weights[option_name] + new_value = new_weights[option] + if isinstance(new_value, set): + cleaned_value.difference_update(new_value) + elif isinstance(new_value, list): + for element in new_value: + cleaned_value.remove(element) + elif isinstance(new_value, dict): + cleaned_value = dict(Counter(cleaned_value) - Counter(new_value)) + else: + raise Exception(f"Cannot apply remove to non-dict, set, or list type {option_name}," + f" received {type(new_value).__name__}.") + cleaned_weights[option_name] = cleaned_value else: cleaned_weights[option_name] = new_weights[option] new_options = set(cleaned_weights) - set(weights) @@ -460,9 +475,11 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b world_type = AutoWorldRegister.world_types[ret.game] game_weights = weights[ret.game] - if any(weight.startswith("+") for weight in game_weights) or \ - any(weight.startswith("+") for weight in weights): - raise Exception(f"Merge tag cannot be used outside of trigger contexts.") + for weight in cycle((game_weights, weights)): + if weight.startswith("+"): + raise Exception(f"Merge tag cannot be used outside of trigger contexts. Found {weight}") + if weight.startswith("-"): + raise Exception(f"Remove tag cannot be used outside of trigger contexts. Found {weight}") if "triggers" in game_weights: weights = roll_triggers(weights, game_weights["triggers"]) From 0b139911368b48a5d0ff92397f43819a6be164be Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 26 Mar 2024 14:52:04 +0100 Subject: [PATCH 3/6] Generate: might be helpful to use the correct function --- Generate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Generate.py b/Generate.py index 7c7130e5d818..17107ba1989a 100644 --- a/Generate.py +++ b/Generate.py @@ -9,7 +9,7 @@ import urllib.request from collections import Counter from typing import Any, Dict, Tuple, Union -from itertools import cycle +from itertools import chain import ModuleUpdate @@ -475,7 +475,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b world_type = AutoWorldRegister.world_types[ret.game] game_weights = weights[ret.game] - for weight in cycle((game_weights, weights)): + for weight in chain(game_weights, weights): if weight.startswith("+"): raise Exception(f"Merge tag cannot be used outside of trigger contexts. Found {weight}") if weight.startswith("-"): From 53532e42ed947ae6dacc15db73494c5a048f1058 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Thu, 23 May 2024 14:19:47 +0200 Subject: [PATCH 4/6] make + dict behave as + for each value --- Generate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Generate.py b/Generate.py index 17107ba1989a..1bd682c6a94b 100644 --- a/Generate.py +++ b/Generate.py @@ -324,10 +324,12 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str if option.startswith("+") and option_name in weights: cleaned_value = weights[option_name] new_value = new_weights[option] - if isinstance(new_value, (set, dict)): + if isinstance(new_value, set): cleaned_value.update(new_value) elif isinstance(new_value, list): cleaned_value.extend(new_value) + elif isinstance(new_value, dict): + cleaned_value = dict(Counter(cleaned_value) + Counter(new_value)) else: raise Exception(f"Cannot apply merge to non-dict, set, or list type {option_name}," f" received {type(new_value).__name__}.") From a5fd645e9bc0181cb3b808157fe0e6761f52ec76 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Thu, 23 May 2024 14:31:06 +0200 Subject: [PATCH 5/6] fix unittest --- test/general/test_player_options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/general/test_player_options.py b/test/general/test_player_options.py index 9650fbe97a95..ea7f19e3d917 100644 --- a/test/general/test_player_options.py +++ b/test/general/test_player_options.py @@ -31,7 +31,7 @@ def test_update_weights(self): self.assertEqual(new_weights["list_2"], ["string_3"]) self.assertEqual(new_weights["list_1"], ["string", "string_2"]) self.assertEqual(new_weights["dict_1"]["option_a"], 50) - self.assertEqual(new_weights["dict_1"]["option_b"], 0) + self.assertEqual(new_weights["dict_1"]["option_b"], 50) self.assertEqual(new_weights["dict_1"]["option_c"], 50) self.assertNotIn("option_f", new_weights["dict_2"]) self.assertEqual(new_weights["dict_2"]["option_g"], 50) From f1a7d84ba18a6c6644ac33039264a25e9dbf49e2 Mon Sep 17 00:00:00 2001 From: Zach Parks Date: Thu, 23 May 2024 07:56:18 -0500 Subject: [PATCH 6/6] Minor clarification to docs and add reference to `-` method. --- worlds/generic/docs/triggers_en.md | 42 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/worlds/generic/docs/triggers_en.md b/worlds/generic/docs/triggers_en.md index 73cca6654328..c084b53fb1d8 100644 --- a/worlds/generic/docs/triggers_en.md +++ b/worlds/generic/docs/triggers_en.md @@ -123,10 +123,21 @@ again using the new options `normal`, `pupdunk_hard`, and `pupdunk_mystery`, and new weights for 150 and 200. This allows for two more triggers that will only be used for the new `pupdunk_hard` and `pupdunk_mystery` options so that they will only be triggered on "pupdunk AND hard/mystery". -Options that define a list, set, or dict can additionally have the character `+` added to the start of their name, which applies the contents of -the activated trigger to the already present equivalents in the game options. +## Adding or Removing from a List, Set, or Dict Option + +List, set, and dict options can additionally have values added to or removed from itself without overriding the existing +option value by prefixing the option name in the trigger block with `+` (add) or `-` (remove). The exact behavior for +each will depend on the option type. + +- For sets, `+` will add the value(s) to the set and `-` will remove any value(s) of the set. Sets do not allow + duplicates. +- For lists, `+` will add new values(s) to the list and `-` will remove the first matching values(s) it comes across. + Lists allow duplicate values. +- For dicts, `+` will add the value(s) to the given key(s) inside the dict if it exists, or add it otherwise. `-` is the + inverse operation of addition (and negative values are allowed). For example: + ```yaml Super Metroid: start_location: @@ -134,18 +145,21 @@ Super Metroid: aqueduct: 50 start_hints: - Morph Ball -triggers: - - option_category: Super Metroid - option_name: start_location - option_result: aqueduct - options: - Super Metroid: - +start_hints: - - Gravity Suit + start_inventory: + Power Bombs: 1 + triggers: + - option_category: Super Metroid + option_name: start_location + option_result: aqueduct + options: + Super Metroid: + +start_hints: + - Gravity Suit ``` -In this example, if the `start_location` option rolls `landing_site`, only a starting hint for Morph Ball will be created. -If `aqueduct` is rolled, a starting hint for Gravity Suit will also be created alongside the hint for Morph Ball. +In this example, if the `start_location` option rolls `landing_site`, only a starting hint for Morph Ball will be +created. If `aqueduct` is rolled, a starting hint for Gravity Suit will also be created alongside the hint for Morph +Ball. -Note that for lists, items can only be added, not removed or replaced. For dicts, defining a value for a present key will -replace that value within the dict. +Note that for lists, items can only be added, not removed or replaced. For dicts, defining a value for a present key +will replace that value within the dict.