From 18fde2a3f3af3f9b5ea97e18df9f3016604e28bd Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 23 Dec 2023 04:23:34 -0600 Subject: [PATCH] Changed Print Template Yaml from checkbox to button --- Gui.py | 2 +- Main.py | 201 +++++++++++------- docs/Customizer.md | 4 +- resources/app/gui/lang/en.json | 2 +- .../gui/randomize/generation/checkboxes.json | 1 - source/classes/constants.py | 1 - source/gui/bottom.py | 37 +++- source/gui/loadcliargs.py | 8 + 8 files changed, 173 insertions(+), 83 deletions(-) diff --git a/Gui.py b/Gui.py index a0aac7af..899935ea 100755 --- a/Gui.py +++ b/Gui.py @@ -45,7 +45,7 @@ def save_settings(gui, args, filename): os.makedirs(settings_path) output_args = {} settings = ["create_rom", "suppress_rom", "bps", "create_spoiler", "suppress_spoiler", - "calc_playthrough", "skip_playthrough", "print_template_yaml", "print_custom_yaml", + "calc_playthrough", "skip_playthrough", "print_custom_yaml", "settingsonload", "rom", "enemizercli", "outputpath"] if filename == "settings.json": for s in settings: diff --git a/Main.py b/Main.py index afcb1568..347aa451 100644 --- a/Main.py +++ b/Main.py @@ -56,32 +56,25 @@ def check_python_version(): def main(args, seed=None, fish=None): check_python_version() + + if args.print_template_yaml: + return export_yaml(args, fish) + if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) output_path.cached_path = args.outputpath start = time.perf_counter() + world = init_world(args, fish) + if args.securerandom: random.use_secure() seeded = False - # initialize the world - if args.code: - for player, code in args.code.items(): - if code: - Settings.adjust_args_from_code(code, player, args) - customized = None - if args.customizer: - customized = CustomSettings() - customized.load_yaml(args.customizer) - seed = customized.determine_seed(seed) + if world.customizer: + seed = world.customizer.determine_seed(seed) seeded = True - customized.adjust_args(args) - world = World(args.multi, args.ow_shuffle, args.ow_crossed, args.ow_mixed, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords, - args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm, - args.accessibility, args.shuffleganon, args.custom, args.customitemarray, args.hints) - world.customizer = customized if customized else None - logger = logging.getLogger('') + world.customizer.adjust_args(args) if seed is None: random.seed(None) world.seed = random.randint(0, 999999999) @@ -93,53 +86,9 @@ def main(args, seed=None, fish=None): if args.securerandom: world.seed = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(9)) - world.boots_hint = args.boots_hint.copy() - world.remote_items = args.remote_items.copy() - world.mapshuffle = args.mapshuffle.copy() - world.compassshuffle = args.compassshuffle.copy() - world.keyshuffle = args.keyshuffle.copy() - world.bigkeyshuffle = args.bigkeyshuffle.copy() - world.bombbag = args.bombbag.copy() - world.flute_mode = args.flute_mode.copy() - world.bow_mode = args.bow_mode.copy() world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)} - world.crystals_ganon_orig = args.crystals_ganon.copy() - world.crystals_gt_orig = args.crystals_gt.copy() - world.owTerrain = args.ow_terrain.copy() - world.owKeepSimilar = args.ow_keepsimilar.copy() - world.owWhirlpoolShuffle = args.ow_whirlpool.copy() - world.owFluteShuffle = args.ow_fluteshuffle.copy() - world.shuffle_bonk_drops = args.bonk_drops.copy() - world.open_pyramid = args.openpyramid.copy() - world.boss_shuffle = args.shufflebosses.copy() - world.enemy_shuffle = args.shuffleenemies.copy() - world.enemy_health = args.enemy_health.copy() - world.enemy_damage = args.enemy_damage.copy() - world.beemizer = args.beemizer.copy() world.intensity = {player: random.randint(1, 3) if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)} - world.door_type_mode = args.door_type_mode.copy() - world.trap_door_mode = args.trap_door_mode.copy() - world.key_logic_algorithm = args.key_logic_algorithm.copy() - world.decoupledoors = args.decoupledoors.copy() - world.door_self_loops = args.door_self_loops.copy() - world.experimental = args.experimental.copy() - world.dungeon_counters = args.dungeon_counters.copy() - world.fish = fish - world.shopsanity = args.shopsanity.copy() - world.dropshuffle = args.dropshuffle.copy() - world.pottery = args.pottery.copy() - world.potshuffle = args.shufflepots.copy() - world.mixed_travel = args.mixed_travel.copy() - world.standardize_palettes = args.standardize_palettes.copy() - world.shufflelinks = args.shufflelinks.copy() - world.shuffletavern = args.shuffletavern.copy() - world.pseudoboots = args.pseudoboots.copy() - world.overworld_map = args.overworld_map.copy() - world.take_any = args.take_any.copy() - world.restrict_boss_items = args.restrict_boss_items.copy() - world.collection_rate = args.collection_rate.copy() - world.colorizepots = args.colorizepots.copy() world.treasure_hunt_count = {} world.treasure_hunt_total = {} @@ -193,27 +142,11 @@ def main(args, seed=None, fish=None): if hasattr(world,"escape_assist") and player in world.escape_assist: world.escape_assist[player].append('bombs') # enemized escape assumes infinite bombs available and will likely be unbeatable without it - if args.usestartinventory[player]: - for tok in filter(None, args.startinventory[player].split(',')): - name = tok.strip() - name = name if name != 'Ocarina' or world.flute_mode[player] != 'active' else 'Ocarina (Activated)' - item = ItemFactory(name, player) - if item: - world.push_precollected(item) - - if world.customizer and world.customizer.get_start_inventory(): - for p, inv_list in world.customizer.get_start_inventory().items(): - for inv_item in inv_list: - item = ItemFactory(inv_item.strip(), p) - if item: - world.push_precollected(item) + set_starting_inventory(world, args) world.settings = CustomSettings() world.settings.create_from_world(world, args) - if args.print_template_yaml: - world.settings.record_item_pool(world, True) - world.settings.write_to_file(output_path(f'{outfilebase}_template.yaml')) if args.create_spoiler and not args.jsonout: logger.info(world.fish.translate("cli", "cli", "create.meta")) world.spoiler.meta_to_file(output_path(f'{outfilebase}_Spoiler.txt')) @@ -466,6 +399,120 @@ def main(args, seed=None, fish=None): return world +def export_yaml(args, fish): + if args.outputpath: + os.makedirs(args.outputpath, exist_ok=True) + output_path.cached_path = args.outputpath + + outfilebase = f'{args.outputname if args.outputname else "export"}' + logger = logging.getLogger('') + + world = init_world(args, fish) + + from OverworldShuffle import __version__ as ORVersion + logger.info( + world.fish.translate("cli","cli","app.title") + "\n", + ORVersion, + "(%s)" % outfilebase, + Settings.make_code(world, 1) if world.players == 1 else '' + ) + + for k,v in {"DR":__version__,"OR":ORVersion}.items(): + logger.info((k + ' Version:').ljust(16) + '%s' % v) + + set_starting_inventory(world, args) + + world.settings = CustomSettings() + world.settings.create_from_world(world, args) + + world.settings.record_item_pool(world, True) + world.settings.write_to_file(output_path(f'{outfilebase}.yaml')) + + return world + + +def init_world(args, fish): + if args.code: + for player, code in args.code.items(): + if code: + Settings.adjust_args_from_code(code, player, args) + + world = World(args.multi, args.ow_shuffle, args.ow_crossed, args.ow_mixed, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords, + args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm, + args.accessibility, args.shuffleganon, args.custom, args.customitemarray, args.hints) + + world.boots_hint = args.boots_hint.copy() + world.remote_items = args.remote_items.copy() + world.mapshuffle = args.mapshuffle.copy() + world.compassshuffle = args.compassshuffle.copy() + world.keyshuffle = args.keyshuffle.copy() + world.bigkeyshuffle = args.bigkeyshuffle.copy() + world.bombbag = args.bombbag.copy() + world.flute_mode = args.flute_mode.copy() + world.bow_mode = args.bow_mode.copy() + world.crystals_ganon_orig = args.crystals_ganon.copy() + world.crystals_gt_orig = args.crystals_gt.copy() + world.owTerrain = args.ow_terrain.copy() + world.owKeepSimilar = args.ow_keepsimilar.copy() + world.owWhirlpoolShuffle = args.ow_whirlpool.copy() + world.owFluteShuffle = args.ow_fluteshuffle.copy() + world.shuffle_bonk_drops = args.bonk_drops.copy() + world.open_pyramid = args.openpyramid.copy() + world.boss_shuffle = args.shufflebosses.copy() + world.enemy_shuffle = args.shuffleenemies.copy() + world.enemy_health = args.enemy_health.copy() + world.enemy_damage = args.enemy_damage.copy() + world.beemizer = args.beemizer.copy() + world.intensity = {player: 'random' if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)} + world.door_type_mode = args.door_type_mode.copy() + world.trap_door_mode = args.trap_door_mode.copy() + world.key_logic_algorithm = args.key_logic_algorithm.copy() + world.decoupledoors = args.decoupledoors.copy() + world.door_self_loops = args.door_self_loops.copy() + world.experimental = args.experimental.copy() + world.dungeon_counters = args.dungeon_counters.copy() + world.fish = fish + world.shopsanity = args.shopsanity.copy() + world.dropshuffle = args.dropshuffle.copy() + world.pottery = args.pottery.copy() + world.potshuffle = args.shufflepots.copy() + world.mixed_travel = args.mixed_travel.copy() + world.standardize_palettes = args.standardize_palettes.copy() + world.shufflelinks = args.shufflelinks.copy() + world.shuffletavern = args.shuffletavern.copy() + world.pseudoboots = args.pseudoboots.copy() + world.overworld_map = args.overworld_map.copy() + world.take_any = args.take_any.copy() + world.restrict_boss_items = args.restrict_boss_items.copy() + world.collection_rate = args.collection_rate.copy() + world.colorizepots = args.colorizepots.copy() + + world.customizer = None + if args.customizer: + world.customizer = CustomSettings() + world.customizer.load_yaml(args.customizer) + + return world + + +def set_starting_inventory(world, args): + for player in range(1, world.players + 1): + if args.usestartinventory[player]: + for tok in filter(None, args.startinventory[player].split(',')): + name = tok.strip() + name = name if name != 'Ocarina' or world.flute_mode[player] != 'active' else 'Ocarina (Activated)' + item = ItemFactory(name, player) + if item: + world.push_precollected(item) + + if world.customizer and world.customizer.get_start_inventory(): + for p, inv_list in world.customizer.get_start_inventory().items(): + for inv_item in inv_list: + item = ItemFactory(inv_item.strip(), p) + if item: + world.push_precollected(item) + + def copy_world(world): # ToDo: Not good yet ret = World(world.players, world.owShuffle, world.owCrossed, world.owMixed, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords, diff --git a/docs/Customizer.md b/docs/Customizer.md index 3f3b31e9..c881119f 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -8,11 +8,13 @@ The cli includes a couple arguments to help: `--print_template_yaml` will create a yaml file based on the settings used. This does not contain any seed specific information. +Present on the GUI as `Export Yaml` on the bottom. + `--print_custom_yaml` will create a yaml file based on the seed rolled. Treat it like a spoiler. `--customizer` takes a file as an argument. -Present on the GUI as `Print Customizer Template`, `Print Customizer File`, and `Customizer File` on the Generation Setup tab. +Present on the GUI as `Print Customizer File` and `Customizer File` on the Generation Setup tab. ### meta diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index cc33e73f..9b4a0690 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -234,7 +234,6 @@ "randomizer.generation.createspoiler": "Create Spoiler Log", "randomizer.generation.createrom": "Create Patched ROM", "randomizer.generation.calcplaythrough": "Calculate Playthrough", - "randomizer.generation.print_template_yaml": "Print Customizer Template", "randomizer.generation.print_custom_yaml": "Print Customizer File", "randomizer.generation.settingsonload": "Settings On Load", @@ -391,6 +390,7 @@ "bottom.content.seed": "Seed #", "bottom.content.generationcount": "Count", "bottom.content.go": "Generate Game", + "bottom.content.exportyaml": "Export Yaml", "bottom.content.dialog.error": "Error while creating seed", "bottom.content.dialog.success": "Success", "bottom.content.dialog.success.message": "Rom created successfully.", diff --git a/resources/app/gui/randomize/generation/checkboxes.json b/resources/app/gui/randomize/generation/checkboxes.json index 658ea7f0..6e377027 100644 --- a/resources/app/gui/randomize/generation/checkboxes.json +++ b/resources/app/gui/randomize/generation/checkboxes.json @@ -4,7 +4,6 @@ "bps": { "type": "checkbox" }, "createspoiler": { "type": "checkbox" }, "calcplaythrough": { "type": "checkbox" }, - "print_template_yaml":{ "type": "checkbox" }, "print_custom_yaml": { "type": "checkbox" } } } diff --git a/source/classes/constants.py b/source/classes/constants.py index 6bf5f55e..c8e15532 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -147,7 +147,6 @@ SETTINGSTOPROCESS = { "createspoiler": "create_spoiler", "createrom": "create_rom", "calcplaythrough": "calc_playthrough", - "print_template_yaml": "print_template_yaml", "print_custom_yaml": "print_custom_yaml", "settingsonload": "settingsonload" } diff --git a/source/gui/bottom.py b/source/gui/bottom.py index 9cc05d23..fddc29a1 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -6,7 +6,7 @@ import random import re from CLI import parse_cli from Fill import FillError -from Main import main, EnemizerError +from Main import main, export_yaml, EnemizerError from Utils import local_path, output_path, open_file, update_deprecated_args import source.classes.constants as CONST from source.gui.randomize.multiworld import multiworld_page @@ -155,6 +155,41 @@ def bottom_frame(self, parent, args=None): self.widgets[widget].pieces["button"].pack(side=LEFT) self.widgets[widget].pieces["button"].configure(bg="#CCCCCC") + def exportYaml(): + guiargs = create_guiargs(parent) + # get default values for missing parameters + for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items(): + if k not in vars(guiargs): + setattr(guiargs, k, v) + elif type(v) is dict: # use same settings for every player + setattr(guiargs, k, {player: getattr(guiargs, k) for player in range(1, guiargs.multi + 1)}) + + filename = None + try: + from tkinter import filedialog + filename = filedialog.asksaveasfilename(initialdir=guiargs.outputpath, title="Save file", filetypes=(("Customizer Yamls", "*.yaml"), ("All files", "*.*"))) + if filename is not None and filename != '': + guiargs.outputpath = parent.settings["outputpath"] = os.path.dirname(filename) + guiargs.outputname = os.path.splitext(os.path.basename(filename))[0] + export_yaml(args=guiargs, fish=parent.fish) + except (FillError, EnemizerError, Exception, RuntimeError) as e: + logging.exception(e) + messagebox.showerror(title="Error while exporting yaml", message=str(e)) + else: + if filename is not None and filename != '': + successMsg = "File Exported" + # FIXME: English + messagebox.showinfo(title="Success", message=successMsg) + + ## Export Yaml Button + widget = "exportyaml" + self.widgets[widget] = Empty() + self.widgets[widget].pieces = {} + # button + self.widgets[widget].type = "button" + self.widgets[widget].pieces["button"] = Button(self, command=exportYaml) + self.widgets[widget].pieces["button"].pack(side=LEFT) + def open_output(): if output_path.cached_path is None: if args and args.outputpath: diff --git a/source/gui/loadcliargs.py b/source/gui/loadcliargs.py index e7e217b9..6e6695c0 100644 --- a/source/gui/loadcliargs.py +++ b/source/gui/loadcliargs.py @@ -158,6 +158,14 @@ def loadcliargs(gui, args, settings=None): label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget) gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label) + # Set Export Yaml button + mainpage = "bottom" + subpage = "content" + widget = "exportyaml" + # set textbox/frame label + label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget) + gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label) + # Set Save Settings button mainpage = "bottom" subpage = "content"