244 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| import argparse
 | |
| import os
 | |
| import logging
 | |
| import textwrap
 | |
| import sys
 | |
| import time
 | |
| from tkinter import Tk
 | |
| 
 | |
| from Gui import update_sprites
 | |
| from GuiUtils import BackgroundTaskProgress
 | |
| 
 | |
| from worlds.alttp.Rom import Sprite, LocalRom, apply_rom_settings
 | |
| from Utils import output_path
 | |
| 
 | |
| 
 | |
| class AdjusterWorld(object):
 | |
|     def __init__(self, sprite_pool):
 | |
|         import random
 | |
|         self.sprite_pool = {1: sprite_pool}
 | |
|         self.rom_seeds = {1: random}
 | |
| 
 | |
| 
 | |
| class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
 | |
| 
 | |
|     def _get_help_string(self, action):
 | |
|         return textwrap.dedent(action.help)
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
 | |
| 
 | |
|     parser.add_argument('--rom', default='ER_base.sfc', help='Path to an ALttP rom to adjust.')
 | |
|     parser.add_argument('--baserom', default='Zelda no Densetsu - Kamigami no Triforce (Japan).sfc',
 | |
|                         help='Path to an ALttP JAP(1.0) rom to use as a base.')
 | |
|     parser.add_argument('--loglevel', default='info', const='info', nargs='?',
 | |
|                         choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.')
 | |
|     parser.add_argument('--fastmenu', default='normal', const='normal', nargs='?',
 | |
|                         choices=['normal', 'instant', 'double', 'triple', 'quadruple', 'half'],
 | |
|                         help='''\
 | |
|                              Select the rate at which the menu opens and closes.
 | |
|                              (default: %(default)s)
 | |
|                              ''')
 | |
|     parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
 | |
|     parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
 | |
|     parser.add_argument('--triforcehud', default='hide_goal', const='hide_goal', nargs='?',
 | |
|                         choices=['normal', 'hide_goal', 'hide_required', 'hide_both'],
 | |
|                         help='''\
 | |
|                             Hide the triforce hud in certain circumstances.
 | |
|                             hide_goal will hide the hud until finding a triforce piece, hide_required will hide the total amount needed to win
 | |
|                             (Both can be revealed when speaking to Murahalda)
 | |
|                             (default: %(default)s)
 | |
|                             ''')
 | |
|     parser.add_argument('--enableflashing',
 | |
|                         help='Reenable flashing animations (unfriendly to epilepsy, always disabled in race roms)',
 | |
|                         action='store_false', dest="reduceflashing")
 | |
|     parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?',
 | |
|                         choices=['double', 'normal', 'half', 'quarter', 'off'],
 | |
|                         help='''\
 | |
|                              Select the rate at which the heart beep sound is played at
 | |
|                              low health. (default: %(default)s)
 | |
|                              ''')
 | |
|     parser.add_argument('--heartcolor', default='red', const='red', nargs='?',
 | |
|                         choices=['red', 'blue', 'green', 'yellow', 'random'],
 | |
|                         help='Select the color of Link\'s heart meter. (default: %(default)s)')
 | |
|     parser.add_argument('--ow_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--link_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--shield_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--sword_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--hud_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--uw_palettes', default='default',
 | |
|                         choices=['default', 'random', 'blackout', 'puke', 'classic', 'grayscale', 'negative', 'dizzy',
 | |
|                                  'sick'])
 | |
|     parser.add_argument('--sprite', help='''\
 | |
|                              Path to a sprite sheet to use for Link. Needs to be in
 | |
|                              binary format and have a length of 0x7000 (28672) bytes,
 | |
|                              or 0x7078 (28792) bytes including palette data.
 | |
|                              Alternatively, can be a ALttP Rom patched with a Link
 | |
|                              sprite that will be extracted.
 | |
|                              ''')
 | |
|     parser.add_argument('--names', default='', type=str)
 | |
|     parser.add_argument('--update_sprites', action='store_true', help='Update Sprite Database, then exit.')
 | |
|     args = parser.parse_args()
 | |
|     if args.update_sprites:
 | |
|         run_sprite_update()
 | |
|         sys.exit()
 | |
|     # set up logger
 | |
|     loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[
 | |
|         args.loglevel]
 | |
|     logging.basicConfig(format='%(message)s', level=loglevel)
 | |
| 
 | |
|     if not os.path.isfile(args.rom):
 | |
|         adjustGUI()
 | |
|     else:
 | |
|         if args.sprite is not None and not os.path.isfile(args.sprite) and not Sprite.get_sprite_from_name(args.sprite):
 | |
|             input('Could not find link sprite sheet at given location. \nPress Enter to exit.')
 | |
|             sys.exit(1)
 | |
| 
 | |
|         args, path = adjust(args=args)
 | |
|         from Utils import persistent_store
 | |
|         if isinstance(args.sprite, Sprite):
 | |
|             args.sprite = args.sprite.name
 | |
|         persistent_store("adjuster", "last_settings_3", args)
 | |
| 
 | |
| 
 | |
| def adjust(args):
 | |
|     start = time.perf_counter()
 | |
|     logger = logging.getLogger('Adjuster')
 | |
|     logger.info('Patching ROM.')
 | |
|     vanillaRom = args.baserom
 | |
|     if os.path.splitext(args.rom)[-1].lower() == '.apbp':
 | |
|         import Patch
 | |
|         meta, args.rom = Patch.create_rom_file(args.rom)
 | |
| 
 | |
|     if os.stat(args.rom).st_size in (0x200000, 0x400000) and os.path.splitext(args.rom)[-1].lower() == '.sfc':
 | |
|         rom = LocalRom(args.rom, patch=False, vanillaRom=vanillaRom)
 | |
|     else:
 | |
|         raise RuntimeError(
 | |
|             'Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.')
 | |
|     palettes_options = {}
 | |
|     palettes_options['dungeon'] = args.uw_palettes
 | |
| 
 | |
|     palettes_options['overworld'] = args.ow_palettes
 | |
|     palettes_options['hud'] = args.hud_palettes
 | |
|     palettes_options['sword'] = args.sword_palettes
 | |
|     palettes_options['shield'] = args.shield_palettes
 | |
|     # palettes_options['link']=args.link_palettesvera
 | |
| 
 | |
|     racerom = rom.read_byte(0x180213) > 0
 | |
|     world = None
 | |
|     if hasattr(args, "world"):
 | |
|         world = getattr(args, "world")
 | |
| 
 | |
|     apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic,
 | |
|                        args.sprite, palettes_options, reduceflashing=args.reduceflashing or racerom, world=world)
 | |
|     path = output_path(f'{os.path.basename(args.rom)[:-4]}_adjusted.sfc')
 | |
|     rom.write_to_file(path)
 | |
| 
 | |
|     logger.info('Done. Enjoy.')
 | |
|     logger.debug('Total Time: %s', time.perf_counter() - start)
 | |
| 
 | |
|     return args, path
 | |
| 
 | |
| 
 | |
| def adjustGUI():
 | |
|     from tkinter import Checkbutton, OptionMenu, Toplevel, LabelFrame, PhotoImage, Tk, LEFT, RIGHT, BOTTOM, TOP, \
 | |
|         StringVar, IntVar, Frame, Label, W, E, X, BOTH, Entry, Spinbox, Button, filedialog, messagebox, ttk
 | |
|     from Gui import get_rom_options_frame, get_rom_frame
 | |
|     from GuiUtils import set_icon
 | |
|     from argparse import Namespace
 | |
|     from Main import __version__ as MWVersion
 | |
|     adjustWindow = Tk()
 | |
|     adjustWindow.wm_title("Archipelago %s LttP Adjuster" % MWVersion)
 | |
|     set_icon(adjustWindow)
 | |
| 
 | |
|     rom_options_frame, rom_vars, set_sprite = get_rom_options_frame(adjustWindow)
 | |
| 
 | |
|     bottomFrame2 = Frame(adjustWindow)
 | |
| 
 | |
|     romFrame, romVar = get_rom_frame(adjustWindow)
 | |
| 
 | |
|     romDialogFrame = Frame(adjustWindow)
 | |
|     baseRomLabel2 = Label(romDialogFrame, text='Rom to adjust')
 | |
|     romVar2 = StringVar()
 | |
|     romEntry2 = Entry(romDialogFrame, textvariable=romVar2)
 | |
| 
 | |
|     def RomSelect2():
 | |
|         rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc", ".apbp")), ("All Files", "*")])
 | |
|         romVar2.set(rom)
 | |
| 
 | |
|     romSelectButton2 = Button(romDialogFrame, text='Select Rom', command=RomSelect2)
 | |
|     romDialogFrame.pack(side=TOP, expand=True, fill=X)
 | |
|     baseRomLabel2.pack(side=LEFT)
 | |
|     romEntry2.pack(side=LEFT, expand=True, fill=X)
 | |
|     romSelectButton2.pack(side=LEFT)
 | |
| 
 | |
|     def adjustRom():
 | |
|         guiargs = Namespace()
 | |
|         guiargs.heartbeep = rom_vars.heartbeepVar.get()
 | |
|         guiargs.heartcolor = rom_vars.heartcolorVar.get()
 | |
|         guiargs.fastmenu = rom_vars.fastMenuVar.get()
 | |
|         guiargs.ow_palettes = rom_vars.owPalettesVar.get()
 | |
|         guiargs.uw_palettes = rom_vars.uwPalettesVar.get()
 | |
|         guiargs.hud_palettes = rom_vars.hudPalettesVar.get()
 | |
|         guiargs.sword_palettes = rom_vars.swordPalettesVar.get()
 | |
|         guiargs.shield_palettes = rom_vars.shieldPalettesVar.get()
 | |
|         guiargs.quickswap = bool(rom_vars.quickSwapVar.get())
 | |
|         guiargs.disablemusic = bool(rom_vars.disableMusicVar.get())
 | |
|         guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
 | |
|         guiargs.rom = romVar2.get()
 | |
|         guiargs.baserom = romVar.get()
 | |
|         guiargs.sprite = rom_vars.sprite
 | |
|         if rom_vars.sprite_pool:
 | |
|             guiargs.world = AdjusterWorld(rom_vars.sprite_pool)
 | |
| 
 | |
|         try:
 | |
|             guiargs, path = adjust(args=guiargs)
 | |
|             if rom_vars.sprite_pool:
 | |
|                 guiargs.sprite_pool = rom_vars.sprite_pool
 | |
|                 delattr(guiargs, "world")
 | |
|         except Exception as e:
 | |
|             logging.exception(e)
 | |
|             messagebox.showerror(title="Error while adjusting Rom", message=str(e))
 | |
|         else:
 | |
|             messagebox.showinfo(title="Success", message=f"Rom patched successfully to {path}")
 | |
|             from Utils import persistent_store
 | |
|             from worlds.alttp.Rom import Sprite
 | |
|             if isinstance(guiargs.sprite, Sprite):
 | |
|                 guiargs.sprite = guiargs.sprite.name
 | |
|             persistent_store("adjuster", "last_settings_3", guiargs)
 | |
| 
 | |
|     adjustButton = Button(bottomFrame2, text='Adjust Rom', command=adjustRom)
 | |
|     rom_options_frame.pack(side=TOP)
 | |
|     adjustButton.pack(side=BOTTOM, padx=(5, 5))
 | |
| 
 | |
|     bottomFrame2.pack(side=BOTTOM, pady=(5, 5))
 | |
| 
 | |
|     adjustWindow.mainloop()
 | |
| 
 | |
| 
 | |
| def run_sprite_update():
 | |
|     import threading
 | |
|     done = threading.Event()
 | |
|     top = Tk()
 | |
|     top.withdraw()
 | |
|     BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set())
 | |
|     while not done.isSet():
 | |
|         top.update()
 | |
|     print("Done updating sprites")
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 | 
