Generate: remove tag "-" (#3036)
* Generate: introduce Remove, similar to Merge * make + dict behave as + for each value --------- Co-authored-by: Zach Parks <zach@alliware.com>
This commit is contained in:
parent
3f8c348a49
commit
860ab10b0b
29
Generate.py
29
Generate.py
|
@ -9,6 +9,7 @@ import urllib.parse
|
|||
import urllib.request
|
||||
from collections import Counter
|
||||
from typing import Any, Dict, Tuple, Union
|
||||
from itertools import chain
|
||||
|
||||
import ModuleUpdate
|
||||
|
||||
|
@ -319,18 +320,34 @@ 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]
|
||||
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__}.")
|
||||
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)
|
||||
|
@ -466,9 +483,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 chain(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"], valid_trigger_names)
|
||||
|
|
|
@ -31,7 +31,7 @@ class TestPlayerOptions(unittest.TestCase):
|
|||
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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue