| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | import argparse | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | import random | 
					
						
							|  |  |  | import urllib.request | 
					
						
							|  |  |  | import urllib.parse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from EntranceRandomizer import parse_arguments | 
					
						
							|  |  |  | from Main import main as ERmain | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_yaml(txt): | 
					
						
							| 
									
										
										
										
											2020-01-06 20:14:16 +01:00
										 |  |  |     def strip(s): | 
					
						
							|  |  |  |         s = s.strip() | 
					
						
							|  |  |  |         return '' if not s else s.strip('"') if s[0] == '"' else s.strip("'") if s[0] == "'" else s | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     ret = {} | 
					
						
							| 
									
										
										
										
											2019-12-18 20:41:59 +01:00
										 |  |  |     indents = {len(txt) - len(txt.lstrip(' ')): ret} | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     for line in txt.splitlines(): | 
					
						
							|  |  |  |         if not line: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         name, val = line.split(':', 1) | 
					
						
							| 
									
										
										
										
											2020-01-06 20:14:16 +01:00
										 |  |  |         val = strip(val) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |         spaces = len(name) - len(name.lstrip(' ')) | 
					
						
							| 
									
										
										
										
											2020-01-06 20:14:16 +01:00
										 |  |  |         name = strip(name) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |         if val: | 
					
						
							|  |  |  |             indents[spaces][name] = val | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             newdict = {} | 
					
						
							|  |  |  |             indents[spaces][name] = newdict | 
					
						
							|  |  |  |             indents[spaces+2] = newdict | 
					
						
							|  |  |  |     return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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() | 
					
						
							|  |  |  |     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)) | 
					
						
							|  |  |  |     parser.add_argument('--names', default='') | 
					
						
							| 
									
										
										
										
											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') | 
					
						
							|  |  |  |     parser.add_argument('--rom') | 
					
						
							|  |  |  |     parser.add_argument('--enemizercli') | 
					
						
							|  |  |  |     parser.add_argument('--outputpath') | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     seedname = f'M{random.randint(0, 999999999)}' | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							|  |  |  |         weights_cache[args.weights] = get_weights(args.weights) | 
					
						
							|  |  |  |         print(f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}") | 
					
						
							|  |  |  |     for player in range(1, args.multi + 1): | 
					
						
							|  |  |  |         path = getattr(args, f'p{player}') | 
					
						
							|  |  |  |         if path: | 
					
						
							|  |  |  |             if path not in weights_cache: | 
					
						
							|  |  |  |                 weights_cache[path] = get_weights(path) | 
					
						
							| 
									
										
										
										
											2020-01-28 18:19:07 -04:00
										 |  |  |             print(weights_cache[path]) | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |             print(f"P{player} Weights: {path} >> {weights_cache[path]['description']}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     erargs = parse_arguments(['--multi', str(args.multi)]) | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     erargs.seed = seed | 
					
						
							|  |  |  |     erargs.names = args.names | 
					
						
							|  |  |  |     erargs.create_spoiler = args.create_spoiler | 
					
						
							|  |  |  |     erargs.race = True | 
					
						
							|  |  |  |     erargs.outputname = seedname | 
					
						
							|  |  |  |     erargs.outputpath = args.outputpath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if args.rom: | 
					
						
							|  |  |  |         erargs.rom = args.rom | 
					
						
							| 
									
										
										
										
											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()} | 
					
						
							|  |  |  |     for player in range(1, args.multi + 1): | 
					
						
							|  |  |  |         path = getattr(args, f'p{player}') if getattr(args, f'p{player}') else args.weights | 
					
						
							|  |  |  |         if path: | 
					
						
							|  |  |  |             settings = settings_cache[path] if settings_cache[path] else roll_settings(weights_cache[path]) | 
					
						
							|  |  |  |             for k, v in vars(settings).items(): | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |                 if v is not None: | 
					
						
							|  |  |  |                     getattr(erargs, k)[player] = v | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             raise RuntimeError(f'No weights specified for player {player}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # set up logger | 
					
						
							|  |  |  |     loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel] | 
					
						
							|  |  |  |     logging.basicConfig(format='%(message)s', level=loglevel) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ERmain(erargs, seed) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_weights(path): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2020-01-28 18:19:07 -04:00
										 |  |  |         with open(path, 'rb') as f: | 
					
						
							|  |  |  |             yaml = str(f.read(), "utf-8") | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     except Exception as e: | 
					
						
							|  |  |  |         print('Failed to read weights (%s)' % e) | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return parse_yaml(yaml) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def roll_settings(weights): | 
					
						
							| 
									
										
										
										
											2020-01-06 19:09:46 +01:00
										 |  |  |     def get_choice(option, root=weights): | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |         if option not in root: | 
					
						
							| 
									
										
										
										
											2020-01-09 09:13:50 +01:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-01-06 20:01:03 +01:00
										 |  |  |         if type(root[option]) is not dict: | 
					
						
							|  |  |  |             return root[option] | 
					
						
							|  |  |  |         if not root[option]: | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-01-06 20:14:16 +01:00
										 |  |  |         return random.choices(list(root[option].keys()), weights=list(map(int,root[option].values())))[0] | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ret = argparse.Namespace() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     glitches_required = get_choice('glitches_required') | 
					
						
							| 
									
										
										
										
											2020-01-03 03:49:56 -04:00
										 |  |  |     if glitches_required not in ['none', 'no_logic', 'overworld_glitches']: | 
					
						
							|  |  |  |         print("Only NMG, OWG and No Logic supported") | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         glitches_required = 'none' | 
					
						
							| 
									
										
										
										
											2020-01-03 03:49:56 -04:00
										 |  |  |     ret.logic = {'none': 'noglitches', 'no_logic': 'nologic', 'overworld_glitches': 'owglitches'}[glitches_required] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     item_placement = get_choice('item_placement') | 
					
						
							|  |  |  |     # not supported in ER | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 09:13:50 +01:00
										 |  |  |     dungeon_items = get_choice('dungeon_items') | 
					
						
							|  |  |  |     ret.mapshuffle = get_choice('map_shuffle') == 'on' if 'map_shuffle' in weights else dungeon_items in ['mc', 'mcs', 'full'] | 
					
						
							|  |  |  |     ret.compassshuffle = get_choice('compass_shuffle') == 'on' if 'compass_shuffle' in weights else dungeon_items in ['mc', 'mcs', 'full'] | 
					
						
							|  |  |  |     ret.keyshuffle = get_choice('smallkey_shuffle') == 'on' if 'smallkey_shuffle' in weights else dungeon_items in ['mcs', 'full'] | 
					
						
							|  |  |  |     ret.bigkeyshuffle = get_choice('bigkey_shuffle') == 'on' if 'bigkey_shuffle' in weights else dungeon_items in ['full'] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.accessibility = get_choice('accessibility') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     entrance_shuffle = get_choice('entrance_shuffle') | 
					
						
							| 
									
										
										
										
											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-01-18 10:06:50 +01:00
										 |  |  |     goal = get_choice('goals') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.goal = {'ganon': 'ganon', | 
					
						
							|  |  |  |                 'fast_ganon': 'crystals', | 
					
						
							|  |  |  |                 'dungeons': 'dungeons', | 
					
						
							|  |  |  |                 'pedestal': 'pedestal', | 
					
						
							| 
									
										
										
										
											2019-12-18 20:46:16 +01:00
										 |  |  |                 'triforce-hunt': 'triforcehunt' | 
					
						
							| 
									
										
										
										
											2020-01-18 10:06:50 +01:00
										 |  |  |                 }[goal] | 
					
						
							|  |  |  |     ret.openpyramid = goal == 'fast_ganon' | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.crystals_gt = get_choice('tower_open') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.crystals_ganon =  get_choice('ganon_open') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.mode = get_choice('world_state') | 
					
						
							|  |  |  |     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-01-09 17:46:07 +01:00
										 |  |  |     ret.hints = get_choice('hints') == 'on' | 
					
						
							| 
									
										
										
										
											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-01-09 17:46:07 +01:00
										 |  |  |                   }[get_choice('weapons')] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.difficulty = get_choice('item_pool') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.item_functionality = get_choice('item_functionality') | 
					
						
							| 
									
										
										
										
											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-01-09 17:46:07 +01:00
										 |  |  |                          }[get_choice('boss_shuffle')] | 
					
						
							| 
									
										
										
										
											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-01-09 17:46:07 +01:00
										 |  |  |                           }[get_choice('enemy_shuffle')] | 
					
						
							| 
									
										
										
										
											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-01-09 17:46:07 +01:00
										 |  |  |                         }[get_choice('enemy_damage')] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.enemy_health = get_choice('enemy_health') | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     ret.shufflepots = get_choice('pot_shuffle') == 'on' | 
					
						
							| 
									
										
										
										
											2020-01-09 09:13:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ret.beemizer = int(get_choice('beemizer')) if 'beemizer' in weights else 0 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:03:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-06 19:09:46 +01:00
										 |  |  |     inventoryweights = weights.get('startinventory', {}) | 
					
						
							|  |  |  |     startitems = [] | 
					
						
							|  |  |  |     for item in inventoryweights.keys(): | 
					
						
							|  |  |  |         if get_choice(item, inventoryweights) == 'on': | 
					
						
							|  |  |  |             startitems.append(item) | 
					
						
							|  |  |  |     ret.startinventory = ','.join(startitems) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 17:46:07 +01:00
										 |  |  |     if 'rom' in weights: | 
					
						
							|  |  |  |         romweights = weights['rom'] | 
					
						
							|  |  |  |         ret.sprite = get_choice('sprite', romweights) | 
					
						
							|  |  |  |         ret.disablemusic = get_choice('disablemusic', romweights) == 'on' | 
					
						
							|  |  |  |         ret.quickswap = get_choice('quickswap', romweights) == 'on' | 
					
						
							|  |  |  |         ret.fastmenu = get_choice('menuspeed', romweights) | 
					
						
							|  |  |  |         ret.heartcolor = get_choice('heartcolor', romweights) | 
					
						
							|  |  |  |         ret.heartbeep = get_choice('heartbeep', romweights) | 
					
						
							|  |  |  |         ret.ow_palettes = get_choice('ow_palettes', romweights) | 
					
						
							|  |  |  |         ret.uw_palettes = get_choice('uw_palettes', romweights) | 
					
						
							| 
									
										
										
										
											2019-12-30 03:03:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     return ret | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |