diff --git a/BaseClasses.py b/BaseClasses.py index 2738d3ac6c36..cd8749e11dce 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1352,11 +1352,13 @@ def get_path(state: CollectionState, region: Region) -> List[Union[Tuple[str, st def to_file(self, filename: str) -> None: from itertools import chain from worlds import AutoWorld + from Options import Visibility def write_option(option_key: str, option_obj: Options.AssembleOptions) -> None: res = getattr(self.multiworld.worlds[player].options, option_key) - display_name = getattr(option_obj, "display_name", option_key) - outfile.write(f"{display_name + ':':33}{res.current_option_name}\n") + if res.visibility & Visibility.spoiler: + display_name = getattr(option_obj, "display_name", option_key) + outfile.write(f"{display_name + ':':33}{res.current_option_name}\n") with open(filename, 'w', encoding="utf-8-sig") as outfile: outfile.write( diff --git a/Options.py b/Options.py index e1ae33914332..3b1cdc6e2b62 100644 --- a/Options.py +++ b/Options.py @@ -7,6 +7,7 @@ import numbers import random import typing +import enum from copy import deepcopy from dataclasses import dataclass @@ -20,6 +21,15 @@ import pathlib +class Visibility(enum.IntFlag): + none = 0b0000 + template = 0b0001 + simple_ui = 0b0010 # show option in simple menus, such as player-options + complex_ui = 0b0100 # show option in complex menus, such as weighted-options + spoiler = 0b1000 + all = 0b1111 + + class AssembleOptions(abc.ABCMeta): def __new__(mcs, name, bases, attrs): options = attrs["options"] = {} @@ -102,6 +112,7 @@ def meta__init__(self, *args, **kwargs): class Option(typing.Generic[T], metaclass=AssembleOptions): value: T default: typing.ClassVar[typing.Any] # something that __init__ will be able to convert to the correct type + visibility = Visibility.all # convert option_name_long into Name Long as display_name, otherwise name_long is the result. # Handled in get_option_name() @@ -1115,6 +1126,17 @@ def verify(self, world: typing.Type[World], player_name: str, plando_options: "P link.setdefault("link_replacement", None) +class Removed(FreeText): + """This Option has been Removed.""" + default = "" + visibility = Visibility.none + + def __init__(self, value: str): + if value: + raise Exception("Option removed, please update your options file.") + super().__init__(value) + + @dataclass class PerGameCommonOptions(CommonOptions): local_items: LocalItems @@ -1170,7 +1192,10 @@ def dictify_range(option: Range): for game_name, world in AutoWorldRegister.world_types.items(): if not world.hidden or generate_hidden: - all_options: typing.Dict[str, AssembleOptions] = world.options_dataclass.type_hints + all_options: typing.Dict[str, AssembleOptions] = { + option_name: option for option_name, option in world.options_dataclass.type_hints.items() + if option.visibility & Visibility.template + } with open(local_path("data", "options.yaml")) as f: file_data = f.read() diff --git a/WebHostLib/options.py b/WebHostLib/options.py index 0158de7e241f..b3fd8d612ac0 100644 --- a/WebHostLib/options.py +++ b/WebHostLib/options.py @@ -45,7 +45,15 @@ def get_html_doc(option_type: type(Options.Option)) -> str: } game_options = {} + visible: typing.Set[str] = set() + visible_weighted: typing.Set[str] = set() + for option_name, option in all_options.items(): + if option.visibility & Options.Visibility.simple_ui: + visible.add(option_name) + if option.visibility & Options.Visibility.complex_ui: + visible_weighted.add(option_name) + if option_name in handled_in_js: pass @@ -116,8 +124,6 @@ def get_html_doc(option_type: type(Options.Option)) -> str: else: logging.debug(f"{option} not exported to Web Options.") - player_options["gameOptions"] = game_options - player_options["presetOptions"] = {} for preset_name, preset in world.web.options_presets.items(): player_options["presetOptions"][preset_name] = {} @@ -156,12 +162,23 @@ def get_html_doc(option_type: type(Options.Option)) -> str: os.makedirs(os.path.join(target_folder, 'player-options'), exist_ok=True) + filtered_player_options = player_options + filtered_player_options["gameOptions"] = { + option_name: option_data for option_name, option_data in game_options.items() + if option_name in visible + } + with open(os.path.join(target_folder, 'player-options', game_name + ".json"), "w") as f: - json.dump(player_options, f, indent=2, separators=(',', ': ')) + json.dump(filtered_player_options, f, indent=2, separators=(',', ': ')) + + filtered_player_options["gameOptions"] = { + option_name: option_data for option_name, option_data in game_options.items() + if option_name in visible_weighted + } if not world.hidden and world.web.options_page is True: # Add the random option to Choice, TextChoice, and Toggle options - for option in game_options.values(): + for option in filtered_player_options["gameOptions"].values(): if option["type"] == "select": option["options"].append({"name": "Random", "value": "random"}) @@ -170,7 +187,7 @@ def get_html_doc(option_type: type(Options.Option)) -> str: weighted_options["baseOptions"]["game"][game_name] = 0 weighted_options["games"][game_name] = { - "gameSettings": game_options, + "gameSettings": filtered_player_options["gameOptions"], "gameItems": tuple(world.item_names), "gameItemGroups": [ group for group in world.item_name_groups.keys() if group != "Everything" diff --git a/worlds/alttp/Options.py b/worlds/alttp/Options.py index ff960da66a49..8cb377b7a44f 100644 --- a/worlds/alttp/Options.py +++ b/worlds/alttp/Options.py @@ -2,7 +2,7 @@ from BaseClasses import MultiWorld from Options import Choice, Range, Option, Toggle, DefaultOnToggle, DeathLink, StartInventoryPool, PlandoBosses,\ - FreeText + FreeText, Removed class GlitchesRequired(Choice): @@ -795,4 +795,9 @@ class AllowCollect(DefaultOnToggle): "music": Music, "reduceflashing": ReduceFlashing, "triforcehud": TriforceHud, + + # removed: + "goals": Removed, + "smallkey_shuffle": Removed, + "bigkey_shuffle": Removed, }