| 
									
										
										
										
											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): | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |         val = val.strip() | 
					
						
							|  |  |  |         spaces = len(name) - len(name.lstrip(' ')) | 
					
						
							|  |  |  |         name = name.strip() | 
					
						
							|  |  |  |         if val: | 
					
						
							|  |  |  |             indents[spaces][name] = val | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             newdict = {} | 
					
						
							|  |  |  |             indents[spaces][name] = newdict | 
					
						
							|  |  |  |             indents[spaces+2] = newdict | 
					
						
							|  |  |  |     return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser() | 
					
						
							| 
									
										
										
										
											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='') | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  |     erargs.enemizercli = args.enemizercli | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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(): | 
					
						
							|  |  |  |                 getattr(erargs, k)[player] = v | 
					
						
							|  |  |  |         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: | 
					
						
							|  |  |  |         if urllib.parse.urlparse(path).scheme: | 
					
						
							|  |  |  |             yaml = str(urllib.request.urlopen(path).read(), "utf-8") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def roll_settings(weights): | 
					
						
							|  |  |  |     def get_choice(option): | 
					
						
							|  |  |  |         return random.choices(list(weights[option].keys()), weights=list(map(int,weights[option].values())))[0].replace('"','').replace("'",'') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = argparse.Namespace() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     glitches_required = get_choice('glitches_required') | 
					
						
							|  |  |  |     if glitches_required not in ['none', 'no_logic']: | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |         print("Only NMG and No Logic supported") | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         glitches_required = 'none' | 
					
						
							|  |  |  |     ret.logic = {'none': 'noglitches', 'no_logic': 'nologic'}[glitches_required] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     item_placement = get_choice('item_placement') | 
					
						
							|  |  |  |     # not supported in ER | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-18 20:33:09 +01:00
										 |  |  |     if {'map_shuffle', 'compass_shuffle', 'smallkey_shuffle', 'bigkey_shuffle'}.issubset(weights.keys()): | 
					
						
							|  |  |  |         ret.mapshuffle = get_choice('map_shuffle') == 'on' | 
					
						
							|  |  |  |         ret.compassshuffle = get_choice('compass_shuffle') == 'on' | 
					
						
							|  |  |  |         ret.keyshuffle = get_choice('smallkey_shuffle') == 'on' | 
					
						
							|  |  |  |         ret.bigkeyshuffle = get_choice('bigkey_shuffle') == 'on' | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         dungeon_items = get_choice('dungeon_items') | 
					
						
							|  |  |  |         ret.mapshuffle = dungeon_items in ['mc', 'mcs', 'full'] | 
					
						
							|  |  |  |         ret.compassshuffle = dungeon_items in ['mc', 'mcs', 'full'] | 
					
						
							|  |  |  |         ret.keyshuffle = dungeon_items in ['mcs', 'full'] | 
					
						
							|  |  |  |         ret.bigkeyshuffle = dungeon_items in ['full'] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     accessibility = get_choice('accessibility') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.accessibility = 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
										 |  |  | 
 | 
					
						
							|  |  |  |     goals = 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' | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |                 }[goals] | 
					
						
							| 
									
										
										
										
											2019-12-18 20:34:08 +01:00
										 |  |  |     ret.openpyramid = goals == 'fast_ganon' | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     tower_open = get_choice('tower_open') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.crystals_gt = tower_open | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ganon_open = get_choice('ganon_open') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.crystals_ganon = ganon_open | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     world_state = get_choice('world_state') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.mode = world_state | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  |     if world_state == 'retro': | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |         ret.mode = 'open' | 
					
						
							|  |  |  |         ret.retro = True | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     hints = get_choice('hints') | 
					
						
							| 
									
										
										
										
											2019-12-18 20:41:59 +01:00
										 |  |  |     ret.hints = hints == 'on' | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     weapons = get_choice('weapons') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.swords = {'randomized': 'random', | 
					
						
							|  |  |  |                   'assured': 'assured', | 
					
						
							|  |  |  |                   'vanilla': 'vanilla', | 
					
						
							|  |  |  |                   'swordless': 'swordless' | 
					
						
							|  |  |  |                   }[weapons] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     item_pool = get_choice('item_pool') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.difficulty = item_pool | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     item_functionality = get_choice('item_functionality') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.item_functionality = item_functionality | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     boss_shuffle = get_choice('boss_shuffle') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.shufflebosses = {'none': 'none', | 
					
						
							|  |  |  |                          'simple': 'basic', | 
					
						
							|  |  |  |                          'full': 'normal', | 
					
						
							|  |  |  |                          'random': 'chaos' | 
					
						
							|  |  |  |                          }[boss_shuffle] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     enemy_shuffle = get_choice('enemy_shuffle') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.shuffleenemies = {'none': 'none', | 
					
						
							|  |  |  |                           'shuffled': 'shuffled', | 
					
						
							|  |  |  |                           'random': 'chaos' | 
					
						
							|  |  |  |                           }[enemy_shuffle] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     enemy_damage = get_choice('enemy_damage') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.enemy_damage = {'default': 'default', | 
					
						
							|  |  |  |                         'shuffled': 'shuffled', | 
					
						
							|  |  |  |                         'random': 'chaos' | 
					
						
							|  |  |  |                         }[enemy_damage] | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     enemy_health = get_choice('enemy_health') | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     ret.enemy_health = enemy_health | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:03:53 +01:00
										 |  |  |     ret.beemizer = int(get_choice('beemizer')) if 'beemizer' in weights.keys() else 1 # suck it :) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-17 22:41:19 +01:00
										 |  |  |     return ret | 
					
						
							| 
									
										
										
										
											2019-12-16 02:05:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |