| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | import argparse | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | import random | 
					
						
							|  |  |  | import urllib.request | 
					
						
							|  |  |  | import urllib.parse | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2020-01-25 16:37:29 -08:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ModuleUpdate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ModuleUpdate.update() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-09 05:28:48 +01:00
										 |  |  | from Utils import parse_yaml | 
					
						
							| 
									
										
										
										
											2020-01-25 16:37:29 -08:00
										 |  |  | from Rom import get_sprite_from_name | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | from EntranceRandomizer import parse_arguments | 
					
						
							|  |  |  | from Main import main as ERmain | 
					
						
							| 
									
										
										
										
											2020-06-03 22:13:58 +02:00
										 |  |  | from Items import item_name_groups, item_table | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							| 
									
										
										
										
											2019-12-30 20:43:43 +01:00
										 |  |  |     parser = argparse.ArgumentParser(add_help=False) | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) | 
					
						
							|  |  |  |     multiargs, _ = parser.parse_known_args() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser() | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  |     parser.add_argument('--weights', | 
					
						
							|  |  |  |                         help='Path to the weights file to use for rolling game settings, urls are also valid') | 
					
						
							|  |  |  |     parser.add_argument('--samesettings', help='Rolls settings per weights file rather than per player', | 
					
						
							|  |  |  |                         action='store_true') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     parser.add_argument('--seed', help='Define seed number to generate.', type=int) | 
					
						
							|  |  |  |     parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) | 
					
						
							| 
									
										
										
										
											2020-01-14 10:42:27 +01:00
										 |  |  |     parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     parser.add_argument('--create_spoiler', action='store_true') | 
					
						
							| 
									
										
										
										
											2020-05-31 00:28:03 +02:00
										 |  |  |     parser.add_argument('--skip_playthrough', action='store_true') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     parser.add_argument('--rom') | 
					
						
							|  |  |  |     parser.add_argument('--enemizercli') | 
					
						
							|  |  |  |     parser.add_argument('--outputpath') | 
					
						
							| 
									
										
										
										
											2020-01-13 19:47:30 +01:00
										 |  |  |     parser.add_argument('--race', action='store_true') | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     parser.add_argument('--meta', default=None) | 
					
						
							| 
									
										
										
										
											2020-04-24 17:01:55 -07:00
										 |  |  |     parser.add_argument('--log_output_path', help='Path to store output log') | 
					
						
							|  |  |  |     parser.add_argument('--loglevel', default='info', help='Sets log level') | 
					
						
							| 
									
										
										
										
											2020-06-04 21:12:05 +02:00
										 |  |  |     parser.add_argument('--yaml_output', default=0, type=lambda value: min(max(int(value), 0), 255), | 
					
						
							| 
									
										
										
										
											2020-04-25 02:25:46 +02:00
										 |  |  |                         help='Output rolled mystery results to yaml up to specified number (made for async multiworld)') | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     for player in range(1, multiargs.multi + 1): | 
					
						
							|  |  |  |         parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     if args.seed is None: | 
					
						
							|  |  |  |         random.seed(None) | 
					
						
							|  |  |  |         seed = random.randint(0, 999999999) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         seed = args.seed | 
					
						
							|  |  |  |     random.seed(seed) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     seedname = "M"+(f"{random.randint(0, 999999999)}".zfill(9)) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     weights_cache = {} | 
					
						
							|  |  |  |     if args.weights: | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             weights_cache[args.weights] = get_weights(args.weights) | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             raise ValueError(f"File {args.weights} is destroyed. Please fix your yaml.") from e | 
					
						
							| 
									
										
										
										
											2020-06-18 08:52:31 -07:00
										 |  |  |         print(f"Weights: {args.weights} >> {get_choice('description', weights_cache[args.weights], 'No description specified')}") | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     if args.meta: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             weights_cache[args.meta] = get_weights(args.meta) | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							| 
									
										
										
										
											2020-02-18 09:50:50 +01:00
										 |  |  |             raise ValueError(f"File {args.meta} is destroyed. Please fix your yaml.") from e | 
					
						
							| 
									
										
										
										
											2020-05-11 02:17:18 +02:00
										 |  |  |         meta_weights = weights_cache[args.meta] | 
					
						
							| 
									
										
										
										
											2020-06-18 08:52:31 -07:00
										 |  |  |         print(f"Meta: {args.meta} >> {get_choice('meta_description', meta_weights, 'No description specified')}") | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |         if args.samesettings: | 
					
						
							|  |  |  |             raise Exception("Cannot mix --samesettings with --meta") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     for player in range(1, args.multi + 1): | 
					
						
							|  |  |  |         path = getattr(args, f'p{player}') | 
					
						
							|  |  |  |         if path: | 
					
						
							| 
									
										
										
										
											2020-03-05 02:31:26 +01:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 if path not in weights_cache: | 
					
						
							| 
									
										
										
										
											2020-01-12 17:03:30 +01:00
										 |  |  |                     weights_cache[path] = get_weights(path) | 
					
						
							| 
									
										
										
										
											2020-06-18 08:52:31 -07:00
										 |  |  |                 print(f"P{player} Weights: {path} >> {get_choice('description', weights_cache[path], 'No description specified')}") | 
					
						
							| 
									
										
										
										
											2020-03-05 02:31:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     erargs = parse_arguments(['--multi', str(args.multi)]) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     erargs.seed = seed | 
					
						
							| 
									
										
										
										
											2020-02-26 19:41:05 +01:00
										 |  |  |     erargs.name = {x: "" for x in range(1, args.multi + 1)} # only so it can be overwrittin in mystery | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     erargs.create_spoiler = args.create_spoiler | 
					
						
							| 
									
										
										
										
											2020-01-13 19:47:30 +01:00
										 |  |  |     erargs.race = args.race | 
					
						
							| 
									
										
										
										
											2020-05-31 00:28:03 +02:00
										 |  |  |     erargs.skip_playthrough = args.skip_playthrough | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     erargs.outputname = seedname | 
					
						
							|  |  |  |     erargs.outputpath = args.outputpath | 
					
						
							| 
									
										
										
										
											2020-02-23 07:21:05 +01:00
										 |  |  |     erargs.teams = args.teams | 
					
						
							| 
									
										
										
										
											2020-05-18 03:54:29 +02:00
										 |  |  |     erargs.progression_balancing = {} | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-22 03:04:55 +01:00
										 |  |  |     # set up logger | 
					
						
							| 
									
										
										
										
											2020-04-24 17:01:55 -07:00
										 |  |  |     if args.loglevel: | 
					
						
							|  |  |  |         erargs.loglevel = args.loglevel | 
					
						
							| 
									
										
										
										
											2020-02-22 03:04:55 +01:00
										 |  |  |     loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel] | 
					
						
							| 
									
										
										
										
											2020-05-11 02:17:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 17:01:55 -07:00
										 |  |  |     import sys | 
					
						
							|  |  |  |     class LoggerWriter(object): | 
					
						
							|  |  |  |         def __init__(self, writer): | 
					
						
							|  |  |  |             self._writer = writer | 
					
						
							|  |  |  |             self._msg = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(self, message): | 
					
						
							|  |  |  |             self._msg = self._msg + message | 
					
						
							|  |  |  |             while '\n' in self._msg: | 
					
						
							|  |  |  |                 pos = self._msg.find('\n') | 
					
						
							|  |  |  |                 self._writer(self._msg[:pos]) | 
					
						
							|  |  |  |                 self._msg = self._msg[pos + 1:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def flush(self): | 
					
						
							|  |  |  |             if self._msg != '': | 
					
						
							|  |  |  |                 self._writer(self._msg) | 
					
						
							|  |  |  |                 self._msg = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if args.log_output_path: | 
					
						
							|  |  |  |         log = logging.getLogger("stderr") | 
					
						
							|  |  |  |         log.addHandler(logging.StreamHandler()) | 
					
						
							|  |  |  |         sys.stderr = LoggerWriter(log.error) | 
					
						
							|  |  |  |         os.makedirs(args.log_output_path, exist_ok=True) | 
					
						
							|  |  |  |         logging.basicConfig(format='%(message)s', level=loglevel, filename=os.path.join(args.log_output_path, f"{seed}.log")) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         logging.basicConfig(format='%(message)s', level=loglevel) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     if args.rom: | 
					
						
							|  |  |  |         erargs.rom = args.rom | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-06 18:39:18 +01:00
										 |  |  |     if args.enemizercli: | 
					
						
							|  |  |  |         erargs.enemizercli = args.enemizercli | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     settings_cache = {k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items()} | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     player_path_cache = {} | 
					
						
							|  |  |  |     for player in range(1, args.multi + 1): | 
					
						
							|  |  |  |         player_path_cache[player] = getattr(args, f'p{player}') if getattr(args, f'p{player}') else args.weights | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if args.meta: | 
					
						
							|  |  |  |         for player, path in player_path_cache.items(): | 
					
						
							|  |  |  |             weights_cache[path].setdefault("meta_ignore", []) | 
					
						
							|  |  |  |         meta_weights = weights_cache[args.meta] | 
					
						
							|  |  |  |         for key in meta_weights: | 
					
						
							|  |  |  |             option = get_choice(key, meta_weights) | 
					
						
							|  |  |  |             if option is not None: | 
					
						
							|  |  |  |                 for player, path in player_path_cache.items(): | 
					
						
							| 
									
										
										
										
											2020-05-18 03:54:29 +02:00
										 |  |  |                     players_meta = weights_cache[path].get("meta_ignore", []) | 
					
						
							|  |  |  |                     if key not in players_meta: | 
					
						
							|  |  |  |                         weights_cache[path][key] = option | 
					
						
							|  |  |  |                     elif type(players_meta) == dict and players_meta[key] and option not in players_meta[key]: | 
					
						
							|  |  |  |                         weights_cache[path][key] = option | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for player in range(1, args.multi + 1): | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |         path = player_path_cache[player] | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         if path: | 
					
						
							| 
									
										
										
										
											2020-01-12 17:03:30 +01:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2020-01-30 13:58:01 -08:00
										 |  |  |                 settings = settings_cache[path] if settings_cache[path] else roll_settings(weights_cache[path]) | 
					
						
							| 
									
										
										
										
											2020-03-28 10:43:02 -07:00
										 |  |  |                 if settings.sprite is not None and not os.path.isfile(settings.sprite) and not get_sprite_from_name(settings.sprite): | 
					
						
							| 
									
										
										
										
											2020-04-22 13:52:03 +02:00
										 |  |  |                     logging.warning( | 
					
						
							|  |  |  |                         f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist.") | 
					
						
							| 
									
										
										
										
											2020-01-12 17:03:30 +01:00
										 |  |  |                 for k, v in vars(settings).items(): | 
					
						
							|  |  |  |                     if v is not None: | 
					
						
							|  |  |  |                         getattr(erargs, k)[player] = v | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             raise RuntimeError(f'No weights specified for player {player}') | 
					
						
							| 
									
										
										
										
											2020-02-26 19:41:05 +01:00
										 |  |  |         if not erargs.name[player]: | 
					
						
							|  |  |  |             erargs.name[player] = os.path.split(path)[-1].split(".")[0] | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |     if args.weights: | 
					
						
							| 
									
										
										
										
											2020-04-22 13:52:03 +02:00
										 |  |  |         erargs.names = "" | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) | 
					
						
							|  |  |  |     del (erargs.name) | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |     if args.yaml_output: | 
					
						
							|  |  |  |         import yaml | 
					
						
							|  |  |  |         important = {} | 
					
						
							|  |  |  |         for option, player_settings in vars(erargs).items(): | 
					
						
							|  |  |  |             if type(player_settings) == dict: | 
					
						
							|  |  |  |                 if len(set(player_settings.values())) > 1: | 
					
						
							|  |  |  |                     important[option] = {player: value for player, value in player_settings.items() if | 
					
						
							|  |  |  |                                          player <= args.yaml_output} | 
					
						
							| 
									
										
										
										
											2020-04-25 17:57:20 -07:00
										 |  |  |                 elif len(set(player_settings.values())) > 0: | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |                     important[option] = player_settings[1] | 
					
						
							| 
									
										
										
										
											2020-04-25 17:57:20 -07:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     logging.debug(f"No player settings defined for option '{option}'") | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 if player_settings != "":  # is not empty name | 
					
						
							|  |  |  |                     important[option] = player_settings | 
					
						
							| 
									
										
										
										
											2020-04-25 17:57:20 -07:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     logging.debug(f"No player settings defined for option '{option}'") | 
					
						
							|  |  |  |         if args.outputpath: | 
					
						
							|  |  |  |             os.makedirs(args.outputpath, exist_ok=True) | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |         with open(os.path.join(args.outputpath if args.outputpath else ".", f"mystery_result_{seed}.yaml"), "wt") as f: | 
					
						
							|  |  |  |             yaml.dump(important, f) | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 03:54:29 +02:00
										 |  |  |     erargs.skip_progression_balancing = {player: not balanced for player, balanced in | 
					
						
							|  |  |  |                                          erargs.progression_balancing.items()} | 
					
						
							|  |  |  |     del (erargs.progression_balancing) | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ERmain(erargs, seed) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  | def get_weights(path): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2020-04-10 06:41:32 +02:00
										 |  |  |         if urllib.parse.urlparse(path).scheme: | 
					
						
							|  |  |  |             yaml = str(urllib.request.urlopen(path).read(), "utf-8") | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |             with open(path, 'rb') as f: | 
					
						
							|  |  |  |                 yaml = str(f.read(), "utf-8") | 
					
						
							|  |  |  |     except Exception as e: | 
					
						
							|  |  |  |         print('Failed to read weights (%s)' % e) | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return parse_yaml(yaml) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | def interpret_on_off(value): | 
					
						
							|  |  |  |     return {"on": True, "off": False}.get(value, value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-20 03:29:13 +01:00
										 |  |  | def convert_to_on_off(value): | 
					
						
							|  |  |  |     return {True: "on", False: "off"}.get(value, value) | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:51:38 -07:00
										 |  |  | def get_choice(option, root, value=None) -> typing.Any: | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     if option not in root: | 
					
						
							| 
									
										
										
										
											2020-06-18 08:51:38 -07:00
										 |  |  |         return value | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     if type(root[option]) is not dict: | 
					
						
							|  |  |  |         return interpret_on_off(root[option]) | 
					
						
							|  |  |  |     if not root[option]: | 
					
						
							| 
									
										
										
										
											2020-06-18 08:51:38 -07:00
										 |  |  |         return value | 
					
						
							| 
									
										
										
										
											2020-06-18 19:21:52 -07:00
										 |  |  |     if any(root[option].values()): | 
					
						
							| 
									
										
										
										
											2020-06-18 08:48:33 -07:00
										 |  |  |         return interpret_on_off( | 
					
						
							|  |  |  |             random.choices(list(root[option].keys()), weights=list(map(int, root[option].values())))[0]) | 
					
						
							| 
									
										
										
										
											2020-06-18 08:51:38 -07:00
										 |  |  |     raise RuntimeError(f"All options specified in {option} are weighted as zero.") | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 17:06:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | def handle_name(name: str): | 
					
						
							|  |  |  |     return name.strip().replace(' ', '_') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  | def roll_settings(weights): | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret = argparse.Namespace() | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |     if "linked_options" in weights: | 
					
						
							|  |  |  |         weights = weights.copy()  # make sure we don't write back to other weights sets in same_settings | 
					
						
							|  |  |  |         for option_set in weights["linked_options"]: | 
					
						
							|  |  |  |             if random.random() < (option_set["percentage"] / 100): | 
					
						
							|  |  |  |                 weights.update(option_set["options"]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 20:49:59 -07:00
										 |  |  |     ret.name = get_choice('name', weights) | 
					
						
							|  |  |  |     if ret.name: | 
					
						
							|  |  |  |         ret.name = handle_name(ret.name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     glitches_required = get_choice('glitches_required', weights) | 
					
						
							| 
									
										
										
										
											2020-06-10 19:02:11 +02:00
										 |  |  |     if glitches_required not in ['none', 'no_logic', 'overworld_glitches', 'minor_glitches']: | 
					
						
							| 
									
										
										
										
											2020-04-08 15:07:19 +02:00
										 |  |  |         logging.warning("Only NMG, OWG and No Logic supported") | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         glitches_required = 'none' | 
					
						
							| 
									
										
										
										
											2020-06-10 19:02:11 +02:00
										 |  |  |     ret.logic = {None: 'noglitches', 'none': 'noglitches', 'no_logic': 'nologic', 'overworld_glitches': 'owglitches', | 
					
						
							|  |  |  |                  'minor_glitches' : 'minorglitches'}[ | 
					
						
							| 
									
										
										
										
											2020-04-25 02:24:37 +02:00
										 |  |  |         glitches_required] | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.progression_balancing = get_choice('progression_balancing', weights, True) | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  |     # item_placement = get_choice('item_placement') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     # not supported in ER | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     dungeon_items = get_choice('dungeon_items', weights) | 
					
						
							| 
									
										
										
										
											2020-01-23 08:35:52 +01:00
										 |  |  |     if dungeon_items == 'full' or dungeon_items == True: | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  |         dungeon_items = 'mcsb' | 
					
						
							| 
									
										
										
										
											2020-02-17 13:29:25 -05:00
										 |  |  |     elif dungeon_items == 'standard': | 
					
						
							|  |  |  |         dungeon_items = "" | 
					
						
							| 
									
										
										
										
											2020-01-23 08:35:52 +01:00
										 |  |  |     elif not dungeon_items: | 
					
						
							|  |  |  |         dungeon_items = "" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.mapshuffle = get_choice('map_shuffle', weights, 'm' in dungeon_items) | 
					
						
							|  |  |  |     ret.compassshuffle = get_choice('compass_shuffle', weights, 'c' in dungeon_items) | 
					
						
							|  |  |  |     ret.keyshuffle = get_choice('smallkey_shuffle', weights, 's' in dungeon_items) | 
					
						
							|  |  |  |     ret.bigkeyshuffle = get_choice('bigkey_shuffle', weights, 'b' in dungeon_items) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.accessibility = get_choice('accessibility', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     entrance_shuffle = get_choice('entrance_shuffle', weights) | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     goal = get_choice('goals', weights) | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.goal = {'ganon': 'ganon', | 
					
						
							|  |  |  |                 'fast_ganon': 'crystals', | 
					
						
							|  |  |  |                 'dungeons': 'dungeons', | 
					
						
							|  |  |  |                 'pedestal': 'pedestal', | 
					
						
							| 
									
										
										
										
											2020-06-03 02:19:16 +02:00
										 |  |  |                 'triforce_hunt': 'triforcehunt', | 
					
						
							|  |  |  |                 'triforce-hunt': 'triforcehunt',  # deprecated, moving all goals to `_` | 
					
						
							|  |  |  |                 'local_triforce_hunt': 'localtriforcehunt' | 
					
						
							| 
									
										
										
										
											2020-01-18 10:06:50 +01:00
										 |  |  |                 }[goal] | 
					
						
							|  |  |  |     ret.openpyramid = goal == 'fast_ganon' | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.crystals_gt = get_choice('tower_open', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.crystals_ganon = get_choice('ganon_open', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.triforce_pieces_available = get_choice('triforce_pieces_available', weights, 30) | 
					
						
							| 
									
										
										
										
											2020-06-18 08:48:33 -07:00
										 |  |  |     ret.triforce_pieces_available = min(max(1, int(ret.triforce_pieces_available)), 90) | 
					
						
							| 
									
										
										
										
											2020-06-17 01:02:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.triforce_pieces_required = get_choice('triforce_pieces_required', weights, 20) | 
					
						
							| 
									
										
										
										
											2020-06-18 08:48:33 -07:00
										 |  |  |     ret.triforce_pieces_required = min(max(1, int(ret.triforce_pieces_required)), 90) | 
					
						
							| 
									
										
										
										
											2020-06-07 15:22:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.mode = get_choice('world_state', weights) | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     if ret.mode == 'retro': | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         ret.mode = 'open' | 
					
						
							|  |  |  |         ret.retro = True | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.hints = get_choice('hints', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.swords = {'randomized': 'random', | 
					
						
							|  |  |  |                   'assured': 'assured', | 
					
						
							|  |  |  |                   'vanilla': 'vanilla', | 
					
						
							|  |  |  |                   'swordless': 'swordless' | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |                   }[get_choice('weapons', weights)] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.difficulty = get_choice('item_pool', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.item_functionality = get_choice('item_functionality', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.shufflebosses = {'none': 'none', | 
					
						
							|  |  |  |                          'simple': 'basic', | 
					
						
							|  |  |  |                          'full': 'normal', | 
					
						
							|  |  |  |                          'random': 'chaos' | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |                          }[get_choice('boss_shuffle', weights)] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.shuffleenemies = {'none': 'none', | 
					
						
							|  |  |  |                           'shuffled': 'shuffled', | 
					
						
							|  |  |  |                           'random': 'chaos' | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |                           }[get_choice('enemy_shuffle', weights)] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.enemy_damage = {'default': 'default', | 
					
						
							|  |  |  |                         'shuffled': 'shuffled', | 
					
						
							|  |  |  |                         'random': 'chaos' | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |                         }[get_choice('enemy_damage', weights)] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.enemy_health = get_choice('enemy_health', weights) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 09:14:31 +01:00
										 |  |  |     ret.shufflepots = get_choice('pot_shuffle', weights) | 
					
						
							| 
									
										
										
										
											2020-01-09 09:13:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.beemizer = int(get_choice('beemizer', weights, 0)) | 
					
						
							| 
									
										
										
										
											2019-12-30 03:03:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 13:55:03 +01:00
										 |  |  |     ret.timer = {'none': False, | 
					
						
							|  |  |  |                  None: False, | 
					
						
							|  |  |  |                  False: False, | 
					
						
							| 
									
										
										
										
											2020-02-02 20:10:56 -05:00
										 |  |  |                  'timed': 'timed', | 
					
						
							|  |  |  |                  'timed_ohko': 'timed-ohko', | 
					
						
							|  |  |  |                  'ohko': 'ohko', | 
					
						
							|  |  |  |                  'timed_countdown': 'timed-countdown', | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |                  'display': 'display'}[get_choice('timer', weights, False)] | 
					
						
							| 
									
										
										
										
											2020-02-02 20:10:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.dungeon_counters = get_choice('dungeon_counters', weights, 'default') | 
					
						
							| 
									
										
										
										
											2020-04-12 15:46:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.progressive = convert_to_on_off(get_choice('progressive', weights, 'on')) | 
					
						
							| 
									
										
										
										
											2020-01-06 19:09:46 +01:00
										 |  |  |     inventoryweights = weights.get('startinventory', {}) | 
					
						
							|  |  |  |     startitems = [] | 
					
						
							|  |  |  |     for item in inventoryweights.keys(): | 
					
						
							| 
									
										
										
										
											2020-01-20 09:21:55 -08:00
										 |  |  |         itemvalue = get_choice(item, inventoryweights) | 
					
						
							| 
									
										
										
										
											2020-03-30 08:47:53 +02:00
										 |  |  |         if item.startswith(('Progressive ', 'Small Key ', 'Rupee', 'Piece of Heart', 'Boss Heart Container', | 
					
						
							|  |  |  |                             'Sanctuary Heart Container', 'Arrow', 'Bombs ', 'Bomb ', 'Bottle')) and isinstance( | 
					
						
							| 
									
										
										
										
											2020-04-10 20:58:52 +02:00
										 |  |  |             itemvalue, int): | 
					
						
							| 
									
										
										
										
											2020-01-22 08:29:43 -08:00
										 |  |  |             for i in range(int(itemvalue)): | 
					
						
							| 
									
										
										
										
											2020-01-20 09:21:55 -08:00
										 |  |  |                 startitems.append(item) | 
					
						
							| 
									
										
										
										
											2020-01-22 08:29:43 -08:00
										 |  |  |         elif itemvalue: | 
					
						
							| 
									
										
										
										
											2020-01-06 19:09:46 +01:00
										 |  |  |             startitems.append(item) | 
					
						
							|  |  |  |     ret.startinventory = ','.join(startitems) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.glitch_boots = get_choice('glitch_boots', weights, True) | 
					
						
							| 
									
										
										
										
											2020-06-03 22:13:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 08:55:15 -07:00
										 |  |  |     ret.remote_items = get_choice('remote_items', weights, False) | 
					
						
							| 
									
										
										
										
											2020-03-30 08:47:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-19 16:10:22 -07:00
										 |  |  |     if get_choice("local_keys", weights, "l" in dungeon_items): | 
					
						
							| 
									
										
										
										
											2020-06-19 03:17:54 +02:00
										 |  |  |         ret.local_items = {"Small Keys", "Big Keys"} | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         ret.local_items = set() | 
					
						
							| 
									
										
										
										
											2020-06-03 22:13:58 +02:00
										 |  |  |     for item_name in weights.get('local_items', []): | 
					
						
							|  |  |  |         items = item_name_groups.get(item_name, {item_name}) | 
					
						
							|  |  |  |         for item in items: | 
					
						
							|  |  |  |             if item in item_table: | 
					
						
							|  |  |  |                 ret.local_items.add(item) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 logging.warning(f"Could not force item {item} to be world-local, as it was not recognized.") | 
					
						
							|  |  |  |     ret.local_items = ",".join(ret.local_items) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     if 'rom' in weights: | 
					
						
							|  |  |  |         romweights = weights['rom'] | 
					
						
							|  |  |  |         ret.sprite = get_choice('sprite', romweights) | 
					
						
							| 
									
										
										
										
											2020-01-19 23:30:22 +01:00
										 |  |  |         ret.disablemusic = get_choice('disablemusic', romweights) | 
					
						
							|  |  |  |         ret.quickswap = get_choice('quickswap', romweights) | 
					
						
							| 
									
										
										
										
											2020-01-20 03:36:03 +01:00
										 |  |  |         ret.fastmenu = get_choice('menuspeed', romweights) | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |         ret.heartcolor = get_choice('heartcolor', romweights) | 
					
						
							| 
									
										
										
										
											2020-01-20 03:29:13 +01:00
										 |  |  |         ret.heartbeep = convert_to_on_off(get_choice('heartbeep', romweights)) | 
					
						
							| 
									
										
										
										
											2020-01-20 03:36:03 +01:00
										 |  |  |         ret.ow_palettes = get_choice('ow_palettes', romweights) | 
					
						
							|  |  |  |         ret.uw_palettes = get_choice('uw_palettes', romweights) | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     return ret | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |