diff --git a/BaseClasses.py b/BaseClasses.py index 49310325..a2bf19b5 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2600,6 +2600,56 @@ class Spoiler(object): else: self.doorTypes[(doorNames, player)] = OrderedDict([('player', player), ('doorNames', doorNames), ('type', type)]) + def parse_meta(self): + from Main import __version__ as ERVersion + from OverworldShuffle import __version__ as ORVersion + + self.startinventory = list(map(str, self.world.precollected_items)) + self.metadata = {'version': ERVersion, + 'versions': {'Door':ERVersion, 'Overworld':ORVersion}, + 'logic': self.world.logic, + 'mode': self.world.mode, + 'retro': self.world.retro, + 'bombbag': self.world.bombbag, + 'weapons': self.world.swords, + 'goal': self.world.goal, + 'ow_shuffle': self.world.owShuffle, + 'ow_crossed': self.world.owCrossed, + 'ow_keepsimilar': self.world.owKeepSimilar, + 'ow_mixed': self.world.owMixed, + 'ow_whirlpool': self.world.owWhirlpoolShuffle, + 'ow_fluteshuffle': self.world.owFluteShuffle, + 'shuffle': self.world.shuffle, + 'shuffleganon': self.world.shuffle_ganon, + 'shufflelinks': self.world.shufflelinks, + 'door_shuffle': self.world.doorShuffle, + 'intensity': self.world.intensity, + 'item_pool': self.world.difficulty, + 'item_functionality': self.world.difficulty_adjustments, + 'gt_crystals': self.world.crystals_needed_for_gt, + 'ganon_crystals': self.world.crystals_needed_for_ganon, + 'open_pyramid': self.world.open_pyramid, + 'accessibility': self.world.accessibility, + 'hints': self.world.hints, + 'mapshuffle': self.world.mapshuffle, + 'compassshuffle': self.world.compassshuffle, + 'keyshuffle': self.world.keyshuffle, + 'bigkeyshuffle': self.world.bigkeyshuffle, + 'boss_shuffle': self.world.boss_shuffle, + 'enemy_shuffle': self.world.enemy_shuffle, + 'enemy_health': self.world.enemy_health, + 'enemy_damage': self.world.enemy_damage, + 'potshuffle': self.world.potshuffle, + 'players': self.world.players, + 'teams': self.world.teams, + 'experimental': self.world.experimental, + 'keydropshuffle': self.world.keydropshuffle, + 'shopsanity': self.world.shopsanity, + 'triforcegoal': self.world.treasure_hunt_count, + 'triforcepool': self.world.treasure_hunt_total, + 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} + } + def parse_data(self): self.medallions = OrderedDict() if self.world.players == 1: @@ -2610,8 +2660,6 @@ class Spoiler(object): self.medallions[f'Misery Mire ({self.world.get_player_names(player)})'] = self.world.required_medallions[player][0] self.medallions[f'Turtle Rock ({self.world.get_player_names(player)})'] = self.world.required_medallions[player][1] - self.startinventory = list(map(str, self.world.precollected_items)) - self.locations = OrderedDict() listed_locations = set() @@ -2682,54 +2730,8 @@ class Spoiler(object): for portal in self.world.dungeon_portals[player]: self.set_lobby(portal.name, portal.door.name, player) - from Main import __version__ as ERVersion - from OverworldShuffle import __version__ as ORVersion - self.metadata = {'version': ERVersion, - 'versions': {'Door':ERVersion, 'Overworld':ORVersion}, - 'logic': self.world.logic, - 'mode': self.world.mode, - 'retro': self.world.retro, - 'bombbag': self.world.bombbag, - 'weapons': self.world.swords, - 'goal': self.world.goal, - 'ow_shuffle': self.world.owShuffle, - 'ow_crossed': self.world.owCrossed, - 'ow_keepsimilar': self.world.owKeepSimilar, - 'ow_mixed': self.world.owMixed, - 'ow_whirlpool': self.world.owWhirlpoolShuffle, - 'ow_fluteshuffle': self.world.owFluteShuffle, - 'shuffle': self.world.shuffle, - 'shuffleganon': self.world.shuffle_ganon, - 'shufflelinks': self.world.shufflelinks, - 'door_shuffle': self.world.doorShuffle, - 'intensity': self.world.intensity, - 'item_pool': self.world.difficulty, - 'item_functionality': self.world.difficulty_adjustments, - 'gt_crystals': self.world.crystals_needed_for_gt, - 'ganon_crystals': self.world.crystals_needed_for_ganon, - 'open_pyramid': self.world.open_pyramid, - 'accessibility': self.world.accessibility, - 'hints': self.world.hints, - 'mapshuffle': self.world.mapshuffle, - 'compassshuffle': self.world.compassshuffle, - 'keyshuffle': self.world.keyshuffle, - 'bigkeyshuffle': self.world.bigkeyshuffle, - 'boss_shuffle': self.world.boss_shuffle, - 'enemy_shuffle': self.world.enemy_shuffle, - 'enemy_health': self.world.enemy_health, - 'enemy_damage': self.world.enemy_damage, - 'potshuffle': self.world.potshuffle, - 'players': self.world.players, - 'teams': self.world.teams, - 'experimental': self.world.experimental, - 'keydropshuffle': self.world.keydropshuffle, - 'shopsanity': self.world.shopsanity, - 'triforcegoal': self.world.treasure_hunt_count, - 'triforcepool': self.world.treasure_hunt_total, - 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} - } - def to_json(self): + self.parse_meta() self.parse_data() out = OrderedDict() out['Overworld'] = list(self.overworlds.values()) @@ -2751,8 +2753,8 @@ class Spoiler(object): return json.dumps(out) - def to_file(self, filename): - self.parse_data() + def meta_to_file(self, filename): + self.parse_meta() with open(filename, 'w') as outfile: line_width = 35 outfile.write('ALttP Entrance Randomizer - Seed: %s\n\n' % (self.world.seed)) @@ -2764,9 +2766,6 @@ class Spoiler(object): for player in range(1, self.world.players + 1): if self.world.players > 1: outfile.write('\nPlayer %d: %s\n' % (player, self.world.get_player_names(player))) - if len(self.hashes) > 0: - for team in range(self.world.teams): - outfile.write('%s%s\n' % (f"Hash - {self.world.player_names[player][team]} (Team {team+1}): " if self.world.teams > 1 else 'Hash: ', self.hashes[player, team])) outfile.write('Settings Code:'.ljust(line_width) + '%s\n' % self.metadata["code"][player]) outfile.write('Logic:'.ljust(line_width) + '%s\n' % self.metadata['logic'][player]) outfile.write('Mode:'.ljust(line_width) + '%s\n' % self.metadata['mode'][player]) @@ -2812,14 +2811,28 @@ class Spoiler(object): if self.startinventory: outfile.write('Starting Inventory:'.ljust(line_width)) outfile.write('\n'.ljust(line_width+1).join(self.startinventory)) - + + def to_file(self, filename): + self.parse_data() + with open(filename, 'a') as outfile: + line_width = 35 + if self.world.players > 1: + outfile.write('\nHashes:') + for player in range(1, self.world.players + 1): + if self.world.players > 1: + outfile.write('\nPlayer %d: %s\n' % (player, self.world.get_player_names(player))) + if len(self.hashes) > 0: + for team in range(self.world.teams): + outfile.write('%s%s\n' % (f"Hash - {self.world.player_names[player][team]} (Team {team+1}): " if self.world.teams > 1 else 'Hash: ', self.hashes[player, team])) outfile.write('\n\nRequirements:\n\n') for dungeon, medallion in self.medallions.items(): outfile.write(f'{dungeon}:'.ljust(line_width) + '%s Medallion\n' % medallion) - if self.world.crystals_gt_orig[player] == 'random': - outfile.write('Crystals Required for GT:'.ljust(line_width) + '%s\n' % (str(self.metadata['gt_crystals'][player]))) - if self.world.crystals_ganon_orig[player] == 'random': - outfile.write('Crystals Required for Ganon:'.ljust(line_width) + '%s\n' % (str(self.metadata['ganon_crystals'][player]))) + for player in range(1, self.world.players + 1): + player_name = '' if self.world.players == 1 else str(' (Player ' + str(player) + ')') + if self.world.crystals_gt_orig[player] == 'random': + outfile.write(str('Crystals Required for GT' + player_name + ':').ljust(line_width) + '%s\n' % (str(self.metadata['gt_crystals'][player]))) + if self.world.crystals_ganon_orig[player] == 'random': + outfile.write(str('Crystals Required for Ganon' + player_name + ':').ljust(line_width) + '%s\n' % (str(self.metadata['ganon_crystals'][player]))) if self.overworlds: # overworlds: overworld transitions; @@ -2868,6 +2881,8 @@ class Spoiler(object): outfile.write(f'\n\nBosses ({self.world.get_player_names(player)}):\n\n') outfile.write('\n'.join([f'{x}: {y}' for x, y in bossmap.items() if y not in ['Agahnim', 'Agahnim 2', 'Ganon']])) + def playthru_to_file(self, filename): + with open(filename, 'a') as outfile: # locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name # items: Item names outfile.write('\n\nPlaythrough:\n\n') @@ -2896,7 +2911,6 @@ class Spoiler(object): outfile.write('\n'.join(path_listings)) - flooded_keys = { 'Trench 1 Switch': 'Swamp Palace - Trench 1 Pot Key', 'Trench 2 Switch': 'Swamp Palace - Trench 2 Pot Key' diff --git a/Main.py b/Main.py index 9827efb1..b5740bf4 100644 --- a/Main.py +++ b/Main.py @@ -131,6 +131,15 @@ def main(args, seed=None, fish=None): world.player_names[player].append(name) logger.info('') + if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] not in ['none', 'polar'] or world.owMixed[1] or str(world.seed).startswith('M'): + outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' + else: + outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' + + if args.create_spoiler and not args.jsonout: + logger.info(world.fish.translate("cli","cli","patching.spoiler")) + world.spoiler.meta_to_file(output_path('%s_Spoiler.txt' % outfilebase)) + for player in range(1, world.players + 1): world.difficulty_requirements[player] = difficulties[world.difficulty[player]] @@ -266,11 +275,6 @@ def main(args, seed=None, fish=None): customize_shops(world, player) balance_money_progression(world) - if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] not in ['none', 'polar'] or world.owMixed[1] or str(world.seed).startswith('M'): - outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' - else: - outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' - rom_names = [] jsonout = {} enemized = False @@ -338,6 +342,10 @@ def main(args, seed=None, fish=None): with open(output_path('%s_multidata' % outfilebase), 'wb') as f: f.write(multidata) + if args.create_spoiler and not args.jsonout: + logger.info(world.fish.translate("cli","cli","patching.spoiler")) + world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) + if not args.skip_playthrough: logger.info(world.fish.translate("cli","cli","calc.playthrough")) create_playthrough(world) @@ -350,7 +358,7 @@ def main(args, seed=None, fish=None): with open(output_path('%s_Spoiler.json' % outfilebase), 'w') as outfile: outfile.write(world.spoiler.to_json()) else: - world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) + world.spoiler.playthru_to_file(output_path('%s_Spoiler.txt' % outfilebase)) YES = world.fish.translate("cli","cli","yes") NO = world.fish.translate("cli","cli","no")