| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | from __future__ import annotations | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2021-06-08 14:15:23 +02:00
										 |  |  | import random | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | class AssembleOptions(type): | 
					
						
							| 
									
										
										
										
											2021-04-14 17:51:11 +02:00
										 |  |  |     def __new__(mcs, name, bases, attrs): | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         options = attrs["options"] = {} | 
					
						
							|  |  |  |         name_lookup = attrs["name_lookup"] = {} | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |         # merge parent class options | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         for base in bases: | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             if getattr(base, "options", None): | 
					
						
							| 
									
										
										
										
											2021-06-08 21:58:11 +02:00
										 |  |  |                 options.update(base.options) | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |                 name_lookup.update(base.name_lookup) | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         new_options = {name[7:].lower(): option_id for name, option_id in attrs.items() if | 
					
						
							| 
									
										
										
										
											2021-03-21 00:47:17 +01:00
										 |  |  |                        name.startswith("option_")} | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |         if "random" in new_options: | 
					
						
							|  |  |  |             raise Exception("Choice option 'random' cannot be manually assigned.") | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         attrs["name_lookup"].update({option_id: name for name, option_id in new_options.items()}) | 
					
						
							|  |  |  |         options.update(new_options) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-21 00:47:17 +01:00
										 |  |  |         # apply aliases, without name_lookup | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         options.update({name[6:].lower(): option_id for name, option_id in attrs.items() if | 
					
						
							|  |  |  |                         name.startswith("alias_")}) | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # auto-validate schema on __init__ | 
					
						
							|  |  |  |         if "schema" in attrs.keys(): | 
					
						
							|  |  |  |             def validate_decorator(func): | 
					
						
							|  |  |  |                 def validate(self, *args, **kwargs): | 
					
						
							|  |  |  |                     func(self, *args, **kwargs) | 
					
						
							|  |  |  |                     self.value = self.schema.validate(self.value) | 
					
						
							|  |  |  |                 return validate | 
					
						
							|  |  |  |             attrs["__init__"] = validate_decorator(attrs["__init__"]) | 
					
						
							| 
									
										
										
										
											2021-04-14 17:51:11 +02:00
										 |  |  |         return super(AssembleOptions, mcs).__new__(mcs, name, bases, attrs) | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | class Option(metaclass=AssembleOptions): | 
					
						
							|  |  |  |     value: int | 
					
						
							|  |  |  |     name_lookup: typing.Dict[int, str] | 
					
						
							| 
									
										
										
										
											2021-04-03 14:47:49 +02:00
										 |  |  |     default = 0 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |     # convert option_name_long into Name Long as displayname, otherwise name_long is the result. | 
					
						
							|  |  |  |     # Handled in get_option_name() | 
					
						
							|  |  |  |     autodisplayname = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     # can be weighted between selections | 
					
						
							|  |  |  |     supports_weighting = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |     def __repr__(self) -> str: | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |         return f"{self.__class__.__name__}({self.get_current_option_name()})" | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         return hash(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def current_key(self) -> str: | 
					
						
							|  |  |  |         return self.name_lookup[self.value] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |     def get_current_option_name(self) -> str: | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |         """For display purposes.""" | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |         return self.get_option_name(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 22:14:18 +02:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def get_option_name(cls, value: typing.Any) -> str: | 
					
						
							|  |  |  |         if cls.autodisplayname: | 
					
						
							|  |  |  |             return cls.name_lookup[value].replace("_", " ").title() | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2021-08-31 22:14:18 +02:00
										 |  |  |             return cls.name_lookup[value] | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |     def __int__(self) -> int: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         return self.value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |     def __bool__(self) -> bool: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         return bool(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 08:38:02 +01:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any): | 
					
						
							|  |  |  |         raise NotImplementedError | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Toggle(Option): | 
					
						
							|  |  |  |     option_false = 0 | 
					
						
							|  |  |  |     option_true = 1 | 
					
						
							| 
									
										
										
										
											2021-04-03 14:47:49 +02:00
										 |  |  |     default = 0 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: int): | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |         assert value == 0 or value == 1 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         self.value = value | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str) -> Toggle: | 
					
						
							|  |  |  |         if text.lower() in {"off", "0", "false", "none", "null", "no"}: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |             return cls(0) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return cls(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 08:38:02 +01:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any): | 
					
						
							|  |  |  |         if type(data) == str: | 
					
						
							|  |  |  |             return cls.from_text(data) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, Toggle): | 
					
						
							|  |  |  |             return self.value == other.value | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return self.value == other | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, Toggle): | 
					
						
							|  |  |  |             return self.value > other.value | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |             return self.value > other | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-21 00:47:17 +01:00
										 |  |  |     def __bool__(self): | 
					
						
							|  |  |  |         return bool(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __int__(self): | 
					
						
							|  |  |  |         return int(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 22:52:14 +02:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def get_option_name(cls, value): | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |         return ["No", "Yes"][int(value)] | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 01:00:21 +02:00
										 |  |  | class DefaultOnToggle(Toggle): | 
					
						
							|  |  |  |     default = 1 | 
					
						
							| 
									
										
										
										
											2021-04-03 14:47:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  | class Choice(Option): | 
					
						
							| 
									
										
										
										
											2021-08-03 19:03:41 +02:00
										 |  |  |     autodisplayname = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |     def __init__(self, value: int): | 
					
						
							|  |  |  |         self.value: int = value | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str) -> Choice: | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |         text = text.lower() | 
					
						
							|  |  |  |         # TODO: turn on after most people have adjusted their yamls to no longer have suboptions with "random" in them | 
					
						
							|  |  |  |         # maybe in 0.2? | 
					
						
							|  |  |  |         # if text == "random": | 
					
						
							|  |  |  |         #     return cls(random.choice(list(cls.options.values()))) | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         for optionname, value in cls.options.items(): | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |             if optionname == text: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |                 return cls(value) | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |         raise KeyError( | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |             f'Could not find option "{text}" for "{cls.__name__}", ' | 
					
						
							|  |  |  |             f'known options are {", ".join(f"{option}" for option in cls.name_lookup.values())}') | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 08:38:02 +01:00
										 |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2021-05-09 17:46:26 +02:00
										 |  |  |     def from_any(cls, data: typing.Any) -> Choice: | 
					
						
							| 
									
										
										
										
											2021-04-08 19:53:24 +02:00
										 |  |  |         if type(data) == int and data in cls.options.values(): | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         return cls.from_text(str(data)) | 
					
						
							| 
									
										
										
										
											2021-03-14 08:38:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |     def __eq__(self, other): | 
					
						
							| 
									
										
										
										
											2021-09-04 17:53:09 +02:00
										 |  |  |         if isinstance(other, self.__class__): | 
					
						
							|  |  |  |             return other.value == self.value | 
					
						
							|  |  |  |         elif isinstance(other, str): | 
					
						
							| 
									
										
										
										
											2021-08-30 19:08:10 +02:00
										 |  |  |             assert other in self.options | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             return other == self.current_key | 
					
						
							| 
									
										
										
										
											2021-08-30 23:07:19 +02:00
										 |  |  |         elif isinstance(other, int): | 
					
						
							| 
									
										
										
										
											2021-08-30 19:08:10 +02:00
										 |  |  |             assert other in self.name_lookup | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             return other == self.value | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |         elif isinstance(other, bool): | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             return other == bool(self.value) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise TypeError(f"Can't compare {self.__class__.__name__} with {other.__class__.__name__}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-30 23:07:19 +02:00
										 |  |  |     def __ne__(self, other): | 
					
						
							| 
									
										
										
										
											2021-09-04 17:53:09 +02:00
										 |  |  |         if isinstance(other, self.__class__): | 
					
						
							|  |  |  |             return other.value != self.value | 
					
						
							|  |  |  |         elif isinstance(other, str): | 
					
						
							| 
									
										
										
										
											2021-08-30 23:07:19 +02:00
										 |  |  |             assert other in self.options | 
					
						
							|  |  |  |             return other != self.current_key | 
					
						
							|  |  |  |         elif isinstance(other, int): | 
					
						
							|  |  |  |             assert other in self.name_lookup | 
					
						
							|  |  |  |             return other != self.value | 
					
						
							|  |  |  |         elif isinstance(other, bool): | 
					
						
							|  |  |  |             return other != bool(self.value) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise TypeError(f"Can't compare {self.__class__.__name__} with {other.__class__.__name__}") | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 21:58:11 +02:00
										 |  |  | class Range(Option, int): | 
					
						
							| 
									
										
										
										
											2021-06-08 14:15:23 +02:00
										 |  |  |     range_start = 0 | 
					
						
							|  |  |  |     range_end = 1 | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: int): | 
					
						
							|  |  |  |         if value < self.range_start: | 
					
						
							|  |  |  |             raise Exception(f"{value} is lower than minimum {self.range_start} for option {self.__class__.__name__}") | 
					
						
							|  |  |  |         elif value > self.range_end: | 
					
						
							|  |  |  |             raise Exception(f"{value} is higher than maximum {self.range_end} for option {self.__class__.__name__}") | 
					
						
							| 
									
										
										
										
											2021-06-08 21:58:11 +02:00
										 |  |  |         self.value = value | 
					
						
							| 
									
										
										
										
											2021-06-08 14:15:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str) -> Range: | 
					
						
							| 
									
										
										
										
											2021-06-08 14:48:00 +02:00
										 |  |  |         text = text.lower() | 
					
						
							|  |  |  |         if text.startswith("random"): | 
					
						
							|  |  |  |             if text == "random-low": | 
					
						
							|  |  |  |                 return cls(int(round(random.triangular(cls.range_start, cls.range_end, cls.range_start), 0))) | 
					
						
							|  |  |  |             elif text == "random-high": | 
					
						
							|  |  |  |                 return cls(int(round(random.triangular(cls.range_start, cls.range_end, cls.range_end), 0))) | 
					
						
							| 
									
										
										
										
											2021-06-12 21:05:45 +02:00
										 |  |  |             elif text == "random-middle": | 
					
						
							|  |  |  |                 return cls(int(round(random.triangular(cls.range_start, cls.range_end), 0))) | 
					
						
							| 
									
										
										
										
											2021-06-08 14:48:00 +02:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 return cls(random.randint(cls.range_start, cls.range_end)) | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  |         return cls(int(text)) | 
					
						
							| 
									
										
										
										
											2021-06-08 14:15:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any) -> Range: | 
					
						
							|  |  |  |         if type(data) == int: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         return cls.from_text(str(data)) | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |     def get_option_name(self, value): | 
					
						
							| 
									
										
										
										
											2021-06-08 08:59:06 -05:00
										 |  |  |         return str(self.value) | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 21:58:11 +02:00
										 |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return str(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-09 17:46:26 +02:00
										 |  |  | class OptionNameSet(Option): | 
					
						
							|  |  |  |     default = frozenset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: typing.Set[str]): | 
					
						
							|  |  |  |         self.value: typing.Set[str] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str) -> OptionNameSet: | 
					
						
							|  |  |  |         return cls({option.strip() for option in text.split(",")}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any) -> OptionNameSet: | 
					
						
							|  |  |  |         if type(data) == set: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         return cls.from_text(str(data)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OptionDict(Option): | 
					
						
							|  |  |  |     default = {} | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     supports_weighting = False | 
					
						
							| 
									
										
										
										
											2021-05-09 17:46:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: typing.Dict[str, typing.Any]): | 
					
						
							|  |  |  |         self.value: typing.Dict[str, typing.Any] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Dict[str, typing.Any]) -> OptionDict: | 
					
						
							|  |  |  |         if type(data) == dict: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 19:09:37 +02:00
										 |  |  |     def get_option_name(self, value): | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |         return ", ".join(f"{key}: {value}" for key, value in self.value.items()) | 
					
						
							| 
									
										
										
										
											2021-05-09 17:46:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 15:39:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  | class OptionList(Option, list): | 
					
						
							| 
									
										
											  
											
												Ocarina of Time (#64)
* first commit (not including OoT data files yet)
* added some basic options
* rule parser works now at least
* make sure to commit everything this time
* temporary change to BaseClasses for oot
* overworld location graph builds mostly correctly
* adding oot data files
* commenting out world options until later since they only existed to make the RuleParser work
* conversion functions between AP ids and OOT ids
* world graph outputs
* set scrub prices
* itempool generates, entrances connected, way too many options added
* fixed set_rules and set_shop_rules
* temp baseclasses changes
* Reaches the fill step now, old event-based system retained in case the new way breaks
* Song placements and misc fixes everywhere
* temporary changes to make oot work
* changed root exits for AP fill framework
* prevent infinite recursion due to OoT sharing usage of the address field
* age reachability works hopefully, songs are broken again
* working spoiler log generation on beatable-only
* Logic tricks implemented
* need this for logic tricks
* fixed map/compass being placed on Serenade location
* kill unreachable events before filling the world
* add a bunch of utility functions to prepare for rom patching
* move OptionList into generic options
* fixed some silly bugs with OptionList
* properly seed all random behavior (so far)
* ROM generation working
* fix hints trying to get alttp dungeon hint texts
* continue fixing hints
* add oot to network data package
* change item and location IDs to 66000 and 67000 range respectively
* push removed items to precollected items
* fixed various issues with cross-contamination with multiple world generation
* reenable glitched logic (hopefully)
* glitched world files age-check fix
* cleaned up some get_locations calls
* added token shuffle and scrub shuffle, modified some options slightly to make the parsing work
* reenable MQ dungeons
* fix forest mq exception
* made targeting style an option for now, will be cosmetic later
* reminder to move targeting to cosmetics
* some oot option maintenance
* enabled starting time of day
* fixed issue breaking shop slots in multiworld generation
* added "off" option for text shuffle and hints
* shopsanity functionality restored
* change patch file extension
* remove unnecessary utility functions + imports
* update MIT license
* change option to "patch_uncompressed_rom" instead of "compress_rom"
* compliance with new AutoWorld systems
* Kill only internal events, remove non-internal big poe event in code
* re-add the big poe event and handle it correctly
* remove extra method in Range option
* fix typo
* Starting items, starting with consumables option
* do not remove nonexistent item
* move set_shop_rules to after shop items are placed
* some cleanup
* add retries for song placement
* flagged Skull Mask and Mask of Truth as advancement items
* update OoT to use LogicMixin
* Fixed trying to assign starting items from the wrong players
* fixed song retry step
* improved option handling, comments, and starting item replacements
* DefaultOnToggle writes Yes or No to spoiler
* enable compression of output if Compress executable is present
* clean up compression
* check whether (de)compressor exists before running the process
* allow specification of rom path in host.yaml
* check if decompressed file already exists before decompressing again
* fix triforce hunt generation
* rename all the oot state functions with prefix
* OoT: mark triforce pieces as completion goal for triforce hunt
* added overworld and any-dungeon shuffle for dungeon items
* Hide most unshuffled locations and events from the list of locations in spoiler
* build oot option ranges with a generic function instead of defining each separately
* move oot output-type control to host.yaml instead of individual yamls
* implement dungeon song shuffle
* minor improvements to overworld dungeon item shuffle
* remove random ice trap names in shops, mostly to avoid maintaining a massive censor list
* always output patch file to folder, remove option to generate ROM in preparation for removal
* re-add the fix for infinite recursion due to not being light or dark world
* change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently
* oot: remove item_names and location_names
* oot: minor fixes
* oot: comment out ROM patching
* oot: only add CollectionState objects on creation if actually needed
* main entrance shuffle method and entrances-based rules
* fix entrances based rules
* disable master quest and big poe count options for client compatibility
* use get_player_name instead of get_player_names
* fix OptionList
* fix oot options for new option system
* new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES
* fill AP player name in oot rom with 0 instead of 0xDF
* encode player name with ASCII for fixed-width
* revert oot player name array to 8 bytes per name
* remove Pierre location if fast scarecrow is on
* check player name length
* "free_scarecrow" not "fast_scarecrow"
* OoT locations now properly store the AP ID instead of the oot internal ID
* oot __version__ updates in lockstep with AP version
* pull in unmodified oot cosmetic files
* also grab JSONDump since it's needed apparently
* gather extra needed methods, modify imports
* delete cosmetics log, replace all instances of SettingsList with OOTWorld
* cosmetic options working, except for sound effects (due to ear-safe issues)
* SFX, Music, and Fanfare randomization reenabled
* move OoT data files into the worlds folder
* move Compress and Decompress into oot data folder
* Replace get_all_state with custom method to avoid the cache
* OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues
* set data_version to 0
* make Kokiri Sword shuffle off by default
* reenable "Random Choice" for various cosmetic options
* kill Ruto's Letter turnin if open fountain
also fix for shopsanity
* place Buy Goron/Zora Tunic first in shop shuffle
* make ice traps appear as other items instead of breaking generation
* managed to break ice traps on non-major-only
* only handle ice traps if they are on
* fix shopsanity for non-oot games, and write player name instead of player number
* light arrows hint uses player name instead of player number
* Reenable "skip child zelda" option
* fix entrances_based_rules
* fix ganondorf hint if starting with light arrows
* fix dungeonitem shuffle and shopsanity interaction
* remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group
* force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any
* keep bosses and bombchu bowling chus out of data package
* revert workaround for infinite recursion and fix it properly
* fix shared shop id caches during patching process
* fix shop text box overflows, as much as possible
* add default oot host.yaml option
* add .apz5, .n64, .z64 to gitignore
* Properly document and name all (functioning) OOT options
* clean up some imports
* remove unnecessary files from oot's data
* fix typo in gitignore
* readd the Compress and Decompress utilities, since they are needed for generation
* cleanup of imports and some minor optimizations
* increase shop offset for item IDs to 0xCB
* remove shop item AP ids entirely
* prevent triforce pieces for other players from being received by yourself
* add "excluded" property to Location
* Hint system adapted and reenabled; hints still unseeded
* make hints deterministic with lists instead of sets
* do not allow hints to point to Light Arrows on non-vanilla bridge
* foreign locations hint as their full name in OoT rather than their region
* checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated
* consolidate versioning in Utils
* ice traps appear as major items rather than any progression item
* set prescription and claim check as defaults for adult trade item settings
* add oot options to playerSettings
* allow case-insensitive logic tricks in yaml
* fix oot shopsanity option formatting
* Write OoT override info even if local item, enabling local checks to show up immediately in the client
* implement CollectionState.can_live_dmg for oot glitched logic
* filter item names for invalid characters when patching shops
* make ice traps appear according to the settings of the world they are shuffled into, rather than the original world
* set hidden-spoiler items and locations with Shop items to events
* make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start
* Fix oot Glitched and No Logic generation
* fix indenting
* Greatly reduce displayed cosmetic options
* Change oot data version to 1
* add apz5 distribution to webhost
* print player name if an ALttP dungeon contains a good item for OoT world
* delete unneeded commented code
* remove OcarinaSongs import to satisfy lint
											
										 
											2021-09-02 08:35:05 -04:00
										 |  |  |     default = [] | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     supports_weighting = False | 
					
						
							|  |  |  |     value: list | 
					
						
							| 
									
										
											  
											
												Ocarina of Time (#64)
* first commit (not including OoT data files yet)
* added some basic options
* rule parser works now at least
* make sure to commit everything this time
* temporary change to BaseClasses for oot
* overworld location graph builds mostly correctly
* adding oot data files
* commenting out world options until later since they only existed to make the RuleParser work
* conversion functions between AP ids and OOT ids
* world graph outputs
* set scrub prices
* itempool generates, entrances connected, way too many options added
* fixed set_rules and set_shop_rules
* temp baseclasses changes
* Reaches the fill step now, old event-based system retained in case the new way breaks
* Song placements and misc fixes everywhere
* temporary changes to make oot work
* changed root exits for AP fill framework
* prevent infinite recursion due to OoT sharing usage of the address field
* age reachability works hopefully, songs are broken again
* working spoiler log generation on beatable-only
* Logic tricks implemented
* need this for logic tricks
* fixed map/compass being placed on Serenade location
* kill unreachable events before filling the world
* add a bunch of utility functions to prepare for rom patching
* move OptionList into generic options
* fixed some silly bugs with OptionList
* properly seed all random behavior (so far)
* ROM generation working
* fix hints trying to get alttp dungeon hint texts
* continue fixing hints
* add oot to network data package
* change item and location IDs to 66000 and 67000 range respectively
* push removed items to precollected items
* fixed various issues with cross-contamination with multiple world generation
* reenable glitched logic (hopefully)
* glitched world files age-check fix
* cleaned up some get_locations calls
* added token shuffle and scrub shuffle, modified some options slightly to make the parsing work
* reenable MQ dungeons
* fix forest mq exception
* made targeting style an option for now, will be cosmetic later
* reminder to move targeting to cosmetics
* some oot option maintenance
* enabled starting time of day
* fixed issue breaking shop slots in multiworld generation
* added "off" option for text shuffle and hints
* shopsanity functionality restored
* change patch file extension
* remove unnecessary utility functions + imports
* update MIT license
* change option to "patch_uncompressed_rom" instead of "compress_rom"
* compliance with new AutoWorld systems
* Kill only internal events, remove non-internal big poe event in code
* re-add the big poe event and handle it correctly
* remove extra method in Range option
* fix typo
* Starting items, starting with consumables option
* do not remove nonexistent item
* move set_shop_rules to after shop items are placed
* some cleanup
* add retries for song placement
* flagged Skull Mask and Mask of Truth as advancement items
* update OoT to use LogicMixin
* Fixed trying to assign starting items from the wrong players
* fixed song retry step
* improved option handling, comments, and starting item replacements
* DefaultOnToggle writes Yes or No to spoiler
* enable compression of output if Compress executable is present
* clean up compression
* check whether (de)compressor exists before running the process
* allow specification of rom path in host.yaml
* check if decompressed file already exists before decompressing again
* fix triforce hunt generation
* rename all the oot state functions with prefix
* OoT: mark triforce pieces as completion goal for triforce hunt
* added overworld and any-dungeon shuffle for dungeon items
* Hide most unshuffled locations and events from the list of locations in spoiler
* build oot option ranges with a generic function instead of defining each separately
* move oot output-type control to host.yaml instead of individual yamls
* implement dungeon song shuffle
* minor improvements to overworld dungeon item shuffle
* remove random ice trap names in shops, mostly to avoid maintaining a massive censor list
* always output patch file to folder, remove option to generate ROM in preparation for removal
* re-add the fix for infinite recursion due to not being light or dark world
* change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently
* oot: remove item_names and location_names
* oot: minor fixes
* oot: comment out ROM patching
* oot: only add CollectionState objects on creation if actually needed
* main entrance shuffle method and entrances-based rules
* fix entrances based rules
* disable master quest and big poe count options for client compatibility
* use get_player_name instead of get_player_names
* fix OptionList
* fix oot options for new option system
* new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES
* fill AP player name in oot rom with 0 instead of 0xDF
* encode player name with ASCII for fixed-width
* revert oot player name array to 8 bytes per name
* remove Pierre location if fast scarecrow is on
* check player name length
* "free_scarecrow" not "fast_scarecrow"
* OoT locations now properly store the AP ID instead of the oot internal ID
* oot __version__ updates in lockstep with AP version
* pull in unmodified oot cosmetic files
* also grab JSONDump since it's needed apparently
* gather extra needed methods, modify imports
* delete cosmetics log, replace all instances of SettingsList with OOTWorld
* cosmetic options working, except for sound effects (due to ear-safe issues)
* SFX, Music, and Fanfare randomization reenabled
* move OoT data files into the worlds folder
* move Compress and Decompress into oot data folder
* Replace get_all_state with custom method to avoid the cache
* OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues
* set data_version to 0
* make Kokiri Sword shuffle off by default
* reenable "Random Choice" for various cosmetic options
* kill Ruto's Letter turnin if open fountain
also fix for shopsanity
* place Buy Goron/Zora Tunic first in shop shuffle
* make ice traps appear as other items instead of breaking generation
* managed to break ice traps on non-major-only
* only handle ice traps if they are on
* fix shopsanity for non-oot games, and write player name instead of player number
* light arrows hint uses player name instead of player number
* Reenable "skip child zelda" option
* fix entrances_based_rules
* fix ganondorf hint if starting with light arrows
* fix dungeonitem shuffle and shopsanity interaction
* remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group
* force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any
* keep bosses and bombchu bowling chus out of data package
* revert workaround for infinite recursion and fix it properly
* fix shared shop id caches during patching process
* fix shop text box overflows, as much as possible
* add default oot host.yaml option
* add .apz5, .n64, .z64 to gitignore
* Properly document and name all (functioning) OOT options
* clean up some imports
* remove unnecessary files from oot's data
* fix typo in gitignore
* readd the Compress and Decompress utilities, since they are needed for generation
* cleanup of imports and some minor optimizations
* increase shop offset for item IDs to 0xCB
* remove shop item AP ids entirely
* prevent triforce pieces for other players from being received by yourself
* add "excluded" property to Location
* Hint system adapted and reenabled; hints still unseeded
* make hints deterministic with lists instead of sets
* do not allow hints to point to Light Arrows on non-vanilla bridge
* foreign locations hint as their full name in OoT rather than their region
* checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated
* consolidate versioning in Utils
* ice traps appear as major items rather than any progression item
* set prescription and claim check as defaults for adult trade item settings
* add oot options to playerSettings
* allow case-insensitive logic tricks in yaml
* fix oot shopsanity option formatting
* Write OoT override info even if local item, enabling local checks to show up immediately in the client
* implement CollectionState.can_live_dmg for oot glitched logic
* filter item names for invalid characters when patching shops
* make ice traps appear according to the settings of the world they are shuffled into, rather than the original world
* set hidden-spoiler items and locations with Shop items to events
* make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start
* Fix oot Glitched and No Logic generation
* fix indenting
* Greatly reduce displayed cosmetic options
* Change oot data version to 1
* add apz5 distribution to webhost
* print player name if an ALttP dungeon contains a good item for OoT world
* delete unneeded commented code
* remove OcarinaSongs import to satisfy lint
											
										 
											2021-09-02 08:35:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: typing.List[str, typing.Any]): | 
					
						
							|  |  |  |         self.value = value | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |         super(OptionList, self).__init__() | 
					
						
							| 
									
										
											  
											
												Ocarina of Time (#64)
* first commit (not including OoT data files yet)
* added some basic options
* rule parser works now at least
* make sure to commit everything this time
* temporary change to BaseClasses for oot
* overworld location graph builds mostly correctly
* adding oot data files
* commenting out world options until later since they only existed to make the RuleParser work
* conversion functions between AP ids and OOT ids
* world graph outputs
* set scrub prices
* itempool generates, entrances connected, way too many options added
* fixed set_rules and set_shop_rules
* temp baseclasses changes
* Reaches the fill step now, old event-based system retained in case the new way breaks
* Song placements and misc fixes everywhere
* temporary changes to make oot work
* changed root exits for AP fill framework
* prevent infinite recursion due to OoT sharing usage of the address field
* age reachability works hopefully, songs are broken again
* working spoiler log generation on beatable-only
* Logic tricks implemented
* need this for logic tricks
* fixed map/compass being placed on Serenade location
* kill unreachable events before filling the world
* add a bunch of utility functions to prepare for rom patching
* move OptionList into generic options
* fixed some silly bugs with OptionList
* properly seed all random behavior (so far)
* ROM generation working
* fix hints trying to get alttp dungeon hint texts
* continue fixing hints
* add oot to network data package
* change item and location IDs to 66000 and 67000 range respectively
* push removed items to precollected items
* fixed various issues with cross-contamination with multiple world generation
* reenable glitched logic (hopefully)
* glitched world files age-check fix
* cleaned up some get_locations calls
* added token shuffle and scrub shuffle, modified some options slightly to make the parsing work
* reenable MQ dungeons
* fix forest mq exception
* made targeting style an option for now, will be cosmetic later
* reminder to move targeting to cosmetics
* some oot option maintenance
* enabled starting time of day
* fixed issue breaking shop slots in multiworld generation
* added "off" option for text shuffle and hints
* shopsanity functionality restored
* change patch file extension
* remove unnecessary utility functions + imports
* update MIT license
* change option to "patch_uncompressed_rom" instead of "compress_rom"
* compliance with new AutoWorld systems
* Kill only internal events, remove non-internal big poe event in code
* re-add the big poe event and handle it correctly
* remove extra method in Range option
* fix typo
* Starting items, starting with consumables option
* do not remove nonexistent item
* move set_shop_rules to after shop items are placed
* some cleanup
* add retries for song placement
* flagged Skull Mask and Mask of Truth as advancement items
* update OoT to use LogicMixin
* Fixed trying to assign starting items from the wrong players
* fixed song retry step
* improved option handling, comments, and starting item replacements
* DefaultOnToggle writes Yes or No to spoiler
* enable compression of output if Compress executable is present
* clean up compression
* check whether (de)compressor exists before running the process
* allow specification of rom path in host.yaml
* check if decompressed file already exists before decompressing again
* fix triforce hunt generation
* rename all the oot state functions with prefix
* OoT: mark triforce pieces as completion goal for triforce hunt
* added overworld and any-dungeon shuffle for dungeon items
* Hide most unshuffled locations and events from the list of locations in spoiler
* build oot option ranges with a generic function instead of defining each separately
* move oot output-type control to host.yaml instead of individual yamls
* implement dungeon song shuffle
* minor improvements to overworld dungeon item shuffle
* remove random ice trap names in shops, mostly to avoid maintaining a massive censor list
* always output patch file to folder, remove option to generate ROM in preparation for removal
* re-add the fix for infinite recursion due to not being light or dark world
* change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently
* oot: remove item_names and location_names
* oot: minor fixes
* oot: comment out ROM patching
* oot: only add CollectionState objects on creation if actually needed
* main entrance shuffle method and entrances-based rules
* fix entrances based rules
* disable master quest and big poe count options for client compatibility
* use get_player_name instead of get_player_names
* fix OptionList
* fix oot options for new option system
* new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES
* fill AP player name in oot rom with 0 instead of 0xDF
* encode player name with ASCII for fixed-width
* revert oot player name array to 8 bytes per name
* remove Pierre location if fast scarecrow is on
* check player name length
* "free_scarecrow" not "fast_scarecrow"
* OoT locations now properly store the AP ID instead of the oot internal ID
* oot __version__ updates in lockstep with AP version
* pull in unmodified oot cosmetic files
* also grab JSONDump since it's needed apparently
* gather extra needed methods, modify imports
* delete cosmetics log, replace all instances of SettingsList with OOTWorld
* cosmetic options working, except for sound effects (due to ear-safe issues)
* SFX, Music, and Fanfare randomization reenabled
* move OoT data files into the worlds folder
* move Compress and Decompress into oot data folder
* Replace get_all_state with custom method to avoid the cache
* OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues
* set data_version to 0
* make Kokiri Sword shuffle off by default
* reenable "Random Choice" for various cosmetic options
* kill Ruto's Letter turnin if open fountain
also fix for shopsanity
* place Buy Goron/Zora Tunic first in shop shuffle
* make ice traps appear as other items instead of breaking generation
* managed to break ice traps on non-major-only
* only handle ice traps if they are on
* fix shopsanity for non-oot games, and write player name instead of player number
* light arrows hint uses player name instead of player number
* Reenable "skip child zelda" option
* fix entrances_based_rules
* fix ganondorf hint if starting with light arrows
* fix dungeonitem shuffle and shopsanity interaction
* remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group
* force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any
* keep bosses and bombchu bowling chus out of data package
* revert workaround for infinite recursion and fix it properly
* fix shared shop id caches during patching process
* fix shop text box overflows, as much as possible
* add default oot host.yaml option
* add .apz5, .n64, .z64 to gitignore
* Properly document and name all (functioning) OOT options
* clean up some imports
* remove unnecessary files from oot's data
* fix typo in gitignore
* readd the Compress and Decompress utilities, since they are needed for generation
* cleanup of imports and some minor optimizations
* increase shop offset for item IDs to 0xCB
* remove shop item AP ids entirely
* prevent triforce pieces for other players from being received by yourself
* add "excluded" property to Location
* Hint system adapted and reenabled; hints still unseeded
* make hints deterministic with lists instead of sets
* do not allow hints to point to Light Arrows on non-vanilla bridge
* foreign locations hint as their full name in OoT rather than their region
* checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated
* consolidate versioning in Utils
* ice traps appear as major items rather than any progression item
* set prescription and claim check as defaults for adult trade item settings
* add oot options to playerSettings
* allow case-insensitive logic tricks in yaml
* fix oot shopsanity option formatting
* Write OoT override info even if local item, enabling local checks to show up immediately in the client
* implement CollectionState.can_live_dmg for oot glitched logic
* filter item names for invalid characters when patching shops
* make ice traps appear according to the settings of the world they are shuffled into, rather than the original world
* set hidden-spoiler items and locations with Shop items to events
* make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start
* Fix oot Glitched and No Logic generation
* fix indenting
* Greatly reduce displayed cosmetic options
* Change oot data version to 1
* add apz5 distribution to webhost
* print player name if an ALttP dungeon contains a good item for OoT world
* delete unneeded commented code
* remove OcarinaSongs import to satisfy lint
											
										 
											2021-09-02 08:35:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str): | 
					
						
							|  |  |  |         return cls([option.strip() for option in text.split(",")]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any): | 
					
						
							|  |  |  |         if type(data) == list: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         return cls.from_text(str(data)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_option_name(self, value): | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |         return ", ".join(self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OptionSet(Option, set): | 
					
						
							|  |  |  |     default = frozenset() | 
					
						
							|  |  |  |     supports_weighting = False | 
					
						
							|  |  |  |     value: set | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: typing.Union[typing.Set[str, typing.Any], typing.List[str, typing.Any]]): | 
					
						
							|  |  |  |         self.value = set(value) | 
					
						
							|  |  |  |         super(OptionSet, self).__init__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_text(cls, text: str): | 
					
						
							|  |  |  |         return cls([option.strip() for option in text.split(",")]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Any): | 
					
						
							|  |  |  |         if type(data) == list: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         elif type(data) == set: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         return cls.from_text(str(data)) | 
					
						
							| 
									
										
											  
											
												Ocarina of Time (#64)
* first commit (not including OoT data files yet)
* added some basic options
* rule parser works now at least
* make sure to commit everything this time
* temporary change to BaseClasses for oot
* overworld location graph builds mostly correctly
* adding oot data files
* commenting out world options until later since they only existed to make the RuleParser work
* conversion functions between AP ids and OOT ids
* world graph outputs
* set scrub prices
* itempool generates, entrances connected, way too many options added
* fixed set_rules and set_shop_rules
* temp baseclasses changes
* Reaches the fill step now, old event-based system retained in case the new way breaks
* Song placements and misc fixes everywhere
* temporary changes to make oot work
* changed root exits for AP fill framework
* prevent infinite recursion due to OoT sharing usage of the address field
* age reachability works hopefully, songs are broken again
* working spoiler log generation on beatable-only
* Logic tricks implemented
* need this for logic tricks
* fixed map/compass being placed on Serenade location
* kill unreachable events before filling the world
* add a bunch of utility functions to prepare for rom patching
* move OptionList into generic options
* fixed some silly bugs with OptionList
* properly seed all random behavior (so far)
* ROM generation working
* fix hints trying to get alttp dungeon hint texts
* continue fixing hints
* add oot to network data package
* change item and location IDs to 66000 and 67000 range respectively
* push removed items to precollected items
* fixed various issues with cross-contamination with multiple world generation
* reenable glitched logic (hopefully)
* glitched world files age-check fix
* cleaned up some get_locations calls
* added token shuffle and scrub shuffle, modified some options slightly to make the parsing work
* reenable MQ dungeons
* fix forest mq exception
* made targeting style an option for now, will be cosmetic later
* reminder to move targeting to cosmetics
* some oot option maintenance
* enabled starting time of day
* fixed issue breaking shop slots in multiworld generation
* added "off" option for text shuffle and hints
* shopsanity functionality restored
* change patch file extension
* remove unnecessary utility functions + imports
* update MIT license
* change option to "patch_uncompressed_rom" instead of "compress_rom"
* compliance with new AutoWorld systems
* Kill only internal events, remove non-internal big poe event in code
* re-add the big poe event and handle it correctly
* remove extra method in Range option
* fix typo
* Starting items, starting with consumables option
* do not remove nonexistent item
* move set_shop_rules to after shop items are placed
* some cleanup
* add retries for song placement
* flagged Skull Mask and Mask of Truth as advancement items
* update OoT to use LogicMixin
* Fixed trying to assign starting items from the wrong players
* fixed song retry step
* improved option handling, comments, and starting item replacements
* DefaultOnToggle writes Yes or No to spoiler
* enable compression of output if Compress executable is present
* clean up compression
* check whether (de)compressor exists before running the process
* allow specification of rom path in host.yaml
* check if decompressed file already exists before decompressing again
* fix triforce hunt generation
* rename all the oot state functions with prefix
* OoT: mark triforce pieces as completion goal for triforce hunt
* added overworld and any-dungeon shuffle for dungeon items
* Hide most unshuffled locations and events from the list of locations in spoiler
* build oot option ranges with a generic function instead of defining each separately
* move oot output-type control to host.yaml instead of individual yamls
* implement dungeon song shuffle
* minor improvements to overworld dungeon item shuffle
* remove random ice trap names in shops, mostly to avoid maintaining a massive censor list
* always output patch file to folder, remove option to generate ROM in preparation for removal
* re-add the fix for infinite recursion due to not being light or dark world
* change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently
* oot: remove item_names and location_names
* oot: minor fixes
* oot: comment out ROM patching
* oot: only add CollectionState objects on creation if actually needed
* main entrance shuffle method and entrances-based rules
* fix entrances based rules
* disable master quest and big poe count options for client compatibility
* use get_player_name instead of get_player_names
* fix OptionList
* fix oot options for new option system
* new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES
* fill AP player name in oot rom with 0 instead of 0xDF
* encode player name with ASCII for fixed-width
* revert oot player name array to 8 bytes per name
* remove Pierre location if fast scarecrow is on
* check player name length
* "free_scarecrow" not "fast_scarecrow"
* OoT locations now properly store the AP ID instead of the oot internal ID
* oot __version__ updates in lockstep with AP version
* pull in unmodified oot cosmetic files
* also grab JSONDump since it's needed apparently
* gather extra needed methods, modify imports
* delete cosmetics log, replace all instances of SettingsList with OOTWorld
* cosmetic options working, except for sound effects (due to ear-safe issues)
* SFX, Music, and Fanfare randomization reenabled
* move OoT data files into the worlds folder
* move Compress and Decompress into oot data folder
* Replace get_all_state with custom method to avoid the cache
* OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues
* set data_version to 0
* make Kokiri Sword shuffle off by default
* reenable "Random Choice" for various cosmetic options
* kill Ruto's Letter turnin if open fountain
also fix for shopsanity
* place Buy Goron/Zora Tunic first in shop shuffle
* make ice traps appear as other items instead of breaking generation
* managed to break ice traps on non-major-only
* only handle ice traps if they are on
* fix shopsanity for non-oot games, and write player name instead of player number
* light arrows hint uses player name instead of player number
* Reenable "skip child zelda" option
* fix entrances_based_rules
* fix ganondorf hint if starting with light arrows
* fix dungeonitem shuffle and shopsanity interaction
* remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group
* force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any
* keep bosses and bombchu bowling chus out of data package
* revert workaround for infinite recursion and fix it properly
* fix shared shop id caches during patching process
* fix shop text box overflows, as much as possible
* add default oot host.yaml option
* add .apz5, .n64, .z64 to gitignore
* Properly document and name all (functioning) OOT options
* clean up some imports
* remove unnecessary files from oot's data
* fix typo in gitignore
* readd the Compress and Decompress utilities, since they are needed for generation
* cleanup of imports and some minor optimizations
* increase shop offset for item IDs to 0xCB
* remove shop item AP ids entirely
* prevent triforce pieces for other players from being received by yourself
* add "excluded" property to Location
* Hint system adapted and reenabled; hints still unseeded
* make hints deterministic with lists instead of sets
* do not allow hints to point to Light Arrows on non-vanilla bridge
* foreign locations hint as their full name in OoT rather than their region
* checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated
* consolidate versioning in Utils
* ice traps appear as major items rather than any progression item
* set prescription and claim check as defaults for adult trade item settings
* add oot options to playerSettings
* allow case-insensitive logic tricks in yaml
* fix oot shopsanity option formatting
* Write OoT override info even if local item, enabling local checks to show up immediately in the client
* implement CollectionState.can_live_dmg for oot glitched logic
* filter item names for invalid characters when patching shops
* make ice traps appear according to the settings of the world they are shuffled into, rather than the original world
* set hidden-spoiler items and locations with Shop items to events
* make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start
* Fix oot Glitched and No Logic generation
* fix indenting
* Greatly reduce displayed cosmetic options
* Change oot data version to 1
* add apz5 distribution to webhost
* print player name if an ALttP dungeon contains a good item for OoT world
* delete unneeded commented code
* remove OcarinaSongs import to satisfy lint
											
										 
											2021-09-02 08:35:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     def get_option_name(self, value): | 
					
						
							|  |  |  |         return ", ".join(self.value) | 
					
						
							| 
									
										
											  
											
												Ocarina of Time (#64)
* first commit (not including OoT data files yet)
* added some basic options
* rule parser works now at least
* make sure to commit everything this time
* temporary change to BaseClasses for oot
* overworld location graph builds mostly correctly
* adding oot data files
* commenting out world options until later since they only existed to make the RuleParser work
* conversion functions between AP ids and OOT ids
* world graph outputs
* set scrub prices
* itempool generates, entrances connected, way too many options added
* fixed set_rules and set_shop_rules
* temp baseclasses changes
* Reaches the fill step now, old event-based system retained in case the new way breaks
* Song placements and misc fixes everywhere
* temporary changes to make oot work
* changed root exits for AP fill framework
* prevent infinite recursion due to OoT sharing usage of the address field
* age reachability works hopefully, songs are broken again
* working spoiler log generation on beatable-only
* Logic tricks implemented
* need this for logic tricks
* fixed map/compass being placed on Serenade location
* kill unreachable events before filling the world
* add a bunch of utility functions to prepare for rom patching
* move OptionList into generic options
* fixed some silly bugs with OptionList
* properly seed all random behavior (so far)
* ROM generation working
* fix hints trying to get alttp dungeon hint texts
* continue fixing hints
* add oot to network data package
* change item and location IDs to 66000 and 67000 range respectively
* push removed items to precollected items
* fixed various issues with cross-contamination with multiple world generation
* reenable glitched logic (hopefully)
* glitched world files age-check fix
* cleaned up some get_locations calls
* added token shuffle and scrub shuffle, modified some options slightly to make the parsing work
* reenable MQ dungeons
* fix forest mq exception
* made targeting style an option for now, will be cosmetic later
* reminder to move targeting to cosmetics
* some oot option maintenance
* enabled starting time of day
* fixed issue breaking shop slots in multiworld generation
* added "off" option for text shuffle and hints
* shopsanity functionality restored
* change patch file extension
* remove unnecessary utility functions + imports
* update MIT license
* change option to "patch_uncompressed_rom" instead of "compress_rom"
* compliance with new AutoWorld systems
* Kill only internal events, remove non-internal big poe event in code
* re-add the big poe event and handle it correctly
* remove extra method in Range option
* fix typo
* Starting items, starting with consumables option
* do not remove nonexistent item
* move set_shop_rules to after shop items are placed
* some cleanup
* add retries for song placement
* flagged Skull Mask and Mask of Truth as advancement items
* update OoT to use LogicMixin
* Fixed trying to assign starting items from the wrong players
* fixed song retry step
* improved option handling, comments, and starting item replacements
* DefaultOnToggle writes Yes or No to spoiler
* enable compression of output if Compress executable is present
* clean up compression
* check whether (de)compressor exists before running the process
* allow specification of rom path in host.yaml
* check if decompressed file already exists before decompressing again
* fix triforce hunt generation
* rename all the oot state functions with prefix
* OoT: mark triforce pieces as completion goal for triforce hunt
* added overworld and any-dungeon shuffle for dungeon items
* Hide most unshuffled locations and events from the list of locations in spoiler
* build oot option ranges with a generic function instead of defining each separately
* move oot output-type control to host.yaml instead of individual yamls
* implement dungeon song shuffle
* minor improvements to overworld dungeon item shuffle
* remove random ice trap names in shops, mostly to avoid maintaining a massive censor list
* always output patch file to folder, remove option to generate ROM in preparation for removal
* re-add the fix for infinite recursion due to not being light or dark world
* change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently
* oot: remove item_names and location_names
* oot: minor fixes
* oot: comment out ROM patching
* oot: only add CollectionState objects on creation if actually needed
* main entrance shuffle method and entrances-based rules
* fix entrances based rules
* disable master quest and big poe count options for client compatibility
* use get_player_name instead of get_player_names
* fix OptionList
* fix oot options for new option system
* new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES
* fill AP player name in oot rom with 0 instead of 0xDF
* encode player name with ASCII for fixed-width
* revert oot player name array to 8 bytes per name
* remove Pierre location if fast scarecrow is on
* check player name length
* "free_scarecrow" not "fast_scarecrow"
* OoT locations now properly store the AP ID instead of the oot internal ID
* oot __version__ updates in lockstep with AP version
* pull in unmodified oot cosmetic files
* also grab JSONDump since it's needed apparently
* gather extra needed methods, modify imports
* delete cosmetics log, replace all instances of SettingsList with OOTWorld
* cosmetic options working, except for sound effects (due to ear-safe issues)
* SFX, Music, and Fanfare randomization reenabled
* move OoT data files into the worlds folder
* move Compress and Decompress into oot data folder
* Replace get_all_state with custom method to avoid the cache
* OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues
* set data_version to 0
* make Kokiri Sword shuffle off by default
* reenable "Random Choice" for various cosmetic options
* kill Ruto's Letter turnin if open fountain
also fix for shopsanity
* place Buy Goron/Zora Tunic first in shop shuffle
* make ice traps appear as other items instead of breaking generation
* managed to break ice traps on non-major-only
* only handle ice traps if they are on
* fix shopsanity for non-oot games, and write player name instead of player number
* light arrows hint uses player name instead of player number
* Reenable "skip child zelda" option
* fix entrances_based_rules
* fix ganondorf hint if starting with light arrows
* fix dungeonitem shuffle and shopsanity interaction
* remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group
* force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any
* keep bosses and bombchu bowling chus out of data package
* revert workaround for infinite recursion and fix it properly
* fix shared shop id caches during patching process
* fix shop text box overflows, as much as possible
* add default oot host.yaml option
* add .apz5, .n64, .z64 to gitignore
* Properly document and name all (functioning) OOT options
* clean up some imports
* remove unnecessary files from oot's data
* fix typo in gitignore
* readd the Compress and Decompress utilities, since they are needed for generation
* cleanup of imports and some minor optimizations
* increase shop offset for item IDs to 0xCB
* remove shop item AP ids entirely
* prevent triforce pieces for other players from being received by yourself
* add "excluded" property to Location
* Hint system adapted and reenabled; hints still unseeded
* make hints deterministic with lists instead of sets
* do not allow hints to point to Light Arrows on non-vanilla bridge
* foreign locations hint as their full name in OoT rather than their region
* checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated
* consolidate versioning in Utils
* ice traps appear as major items rather than any progression item
* set prescription and claim check as defaults for adult trade item settings
* add oot options to playerSettings
* allow case-insensitive logic tricks in yaml
* fix oot shopsanity option formatting
* Write OoT override info even if local item, enabling local checks to show up immediately in the client
* implement CollectionState.can_live_dmg for oot glitched logic
* filter item names for invalid characters when patching shops
* make ice traps appear according to the settings of the world they are shuffled into, rather than the original world
* set hidden-spoiler items and locations with Shop items to events
* make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start
* Fix oot Glitched and No Logic generation
* fix indenting
* Greatly reduce displayed cosmetic options
* Change oot data version to 1
* add apz5 distribution to webhost
* print player name if an ALttP dungeon contains a good item for OoT world
* delete unneeded commented code
* remove OcarinaSongs import to satisfy lint
											
										 
											2021-09-02 08:35:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-21 00:47:17 +01:00
										 |  |  | local_objective = Toggle  # local triforce pieces, local dungeon prizes etc. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Accessibility(Choice): | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     """Set rules for reachability of your items/locations.
 | 
					
						
							|  |  |  |     Locations: ensure everything can be reached and acquired. | 
					
						
							|  |  |  |     Items: ensure all logically relevant items can be acquired. | 
					
						
							|  |  |  |     Minimal: ensure what is needed to reach your goal can be acquired."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |     option_locations = 0 | 
					
						
							|  |  |  |     option_items = 1 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     option_minimal = 2 | 
					
						
							|  |  |  |     alias_none = 2 | 
					
						
							|  |  |  |     default = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ProgressionBalancing(DefaultOnToggle): | 
					
						
							|  |  |  |     """A system that moves progression earlier, to try and prevent the player from getting stuck and bored early.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | common_options = { | 
					
						
							|  |  |  |     "progression_balancing": ProgressionBalancing, | 
					
						
							|  |  |  |     "accessibility": Accessibility | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ItemSet(OptionSet): | 
					
						
							|  |  |  |     # implemented by Generate | 
					
						
							|  |  |  |     verify_item_name = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LocalItems(ItemSet): | 
					
						
							|  |  |  |     """Forces these items to be in their native world.""" | 
					
						
							|  |  |  |     displayname = "Local Items" | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  | class NonLocalItems(ItemSet): | 
					
						
							|  |  |  |     """Forces these items to be outside their native world.""" | 
					
						
							|  |  |  |     displayname = "Not Local Items" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StartInventory(OptionDict): | 
					
						
							|  |  |  |     """Start with these items.""" | 
					
						
							|  |  |  |     verify_item_name = True | 
					
						
							|  |  |  |     displayname = "Start Inventory" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StartHints(ItemSet): | 
					
						
							|  |  |  |     """Start with these item's locations prefilled into the !hint command.""" | 
					
						
							|  |  |  |     displayname = "Start Hints" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExcludeLocations(OptionSet): | 
					
						
							|  |  |  |     """Prevent these locations from having an important item""" | 
					
						
							|  |  |  |     displayname = "Excluded Locations" | 
					
						
							|  |  |  |     verify_location_name = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | per_game_common_options = { | 
					
						
							|  |  |  |     # placeholder until they're actually implemented | 
					
						
							|  |  |  |     "local_items": LocalItems, | 
					
						
							|  |  |  |     "non_local_items": NonLocalItems, | 
					
						
							|  |  |  |     "start_inventory": StartInventory, | 
					
						
							|  |  |  |     "start_hints": StartHints, | 
					
						
							|  |  |  |     "exclude_locations": OptionSet | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2021-07-04 16:18:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from worlds.alttp.Options import Logic | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |     import argparse | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-30 18:00:39 +02:00
										 |  |  |     map_shuffle = Toggle | 
					
						
							|  |  |  |     compass_shuffle = Toggle | 
					
						
							| 
									
										
										
										
											2021-06-19 01:00:21 +02:00
										 |  |  |     keyshuffle = Toggle | 
					
						
							| 
									
										
										
										
											2021-08-30 18:00:39 +02:00
										 |  |  |     bigkey_shuffle = Toggle | 
					
						
							| 
									
										
										
										
											2021-06-19 01:00:21 +02:00
										 |  |  |     hints = Toggle | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |     test = argparse.Namespace() | 
					
						
							|  |  |  |     test.logic = Logic.from_text("no_logic") | 
					
						
							| 
									
										
										
										
											2021-08-30 18:00:39 +02:00
										 |  |  |     test.map_shuffle = map_shuffle.from_text("ON") | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |     test.hints = hints.from_text('OFF') | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         test.logic = Logic.from_text("overworld_glitches_typo") | 
					
						
							|  |  |  |     except KeyError as e: | 
					
						
							|  |  |  |         print(e) | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |         test.logic_owg = Logic.from_text("owg") | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |     except KeyError as e: | 
					
						
							|  |  |  |         print(e) | 
					
						
							| 
									
										
										
										
											2021-08-30 18:00:39 +02:00
										 |  |  |     if test.map_shuffle: | 
					
						
							|  |  |  |         print("map_shuffle is on") | 
					
						
							| 
									
										
										
										
											2020-10-24 06:43:35 +02:00
										 |  |  |     print(f"Hints are {bool(test.hints)}") | 
					
						
							| 
									
										
										
										
											2020-03-18 16:15:32 +01:00
										 |  |  |     print(test) |