diff --git a/Adjuster.py b/Adjuster.py new file mode 100644 index 00000000..a5aebf48 --- /dev/null +++ b/Adjuster.py @@ -0,0 +1,49 @@ +import argparse +import os +import logging +import textwrap +import sys + +from AdjusterMain import adjust + +class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter): + + def _get_help_string(self, action): + return textwrap.dedent(action.help) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) + + parser.add_argument('--rom', default='ER_base.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', help='Enable instant menu', action='store_true') + 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('--heartbeep', default='normal', const='normal', nargs='?', choices=['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('--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. + ''') + args = parser.parse_args() + + # ToDo: Validate files further than mere existance + if not os.path.isfile(args.rom): + input('Could not find valid base rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom) + sys.exit(1) + if args.sprite is not None and not os.path.isfile(args.sprite): + input('Could not find link sprite sheet at given location. \nPress Enter to exit.' % args.sprite) + sys.exit(1) + + # 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) + + adjust(args=args) \ No newline at end of file diff --git a/AdjusterMain.py b/AdjusterMain.py new file mode 100644 index 00000000..059bbbb6 --- /dev/null +++ b/AdjusterMain.py @@ -0,0 +1,286 @@ +from collections import OrderedDict +from Utils import output_path +import os +import time +import logging + +class LocalRom(object): + + def __init__(self, file): + if (os.stat(file).st_size == 2097152 and os.path.splitext(file)[-1].lower() == '.sfc'): + self.buffer = bytearray(open(file, 'rb').read()) + else: + raise RuntimeError('Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.') + + def write_byte(self, address, value): + self.buffer[address] = value + + def write_bytes(self, startaddress, values): + for i, value in enumerate(values): + self.write_byte(startaddress + i, value) + + def write_int16_to_rom(self, address, value): + self.write_bytes(address, int16_as_bytes(value)) + + def write_int32_to_rom(self, address, value): + self.write_bytes(address, int32_as_bytes(value)) + + def write_to_file(self, file): + with open(file, 'wb') as outfile: + outfile.write(self.buffer) + + def write_crc(self): + crc = (sum(self.buffer[:0x7FDC] + self.buffer[0x7FE0:]) + 0x01FE) & 0xFFFF + inv = crc ^ 0xFFFF + self.write_bytes(0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF]) + +def write_sprite(rom, sprite): + if len(sprite) == 0x7000: + # sprite file with graphics and without palette data + rom.write_bytes(0x80000, sprite[:0x7000]) + elif len(sprite) == 0x7078: + # sprite file with graphics and palette data + rom.write_bytes(0x80000, sprite[:0x7000]) + rom.write_bytes(0xDD308, sprite[0x7000:]) + rom.write_bytes(0xDEDF5, sprite[0x7036:0x7038]) + rom.write_bytes(0xDEDF7, sprite[0x7054:0x7056]) + elif len(sprite) in [0x100000, 0x200000]: + # full rom with patched sprite, extract it + rom.write_bytes(0x80000, sprite[0x80000:0x87000]) + rom.write_bytes(0xDD308, sprite[0xDD308:0xDD380]) + rom.write_bytes(0xDEDF5, sprite[0xDEDF5:0xDEDF9]) + +def patch_rom(rom, fastmenu=False, quickswap=False, disable_music=False, beep='normal', sprite=None): + # enable instant item menu + if fastmenu: + rom.write_byte(0x180048, 0x01) + # Sound twekas for fastmenu: + rom.write_byte(0x6DD9A, 0x20) + rom.write_byte(0x6DF2A, 0x20) + rom.write_byte(0x6E0E9, 0x20) + else: + rom.write_byte(0x180048, 0x00) + # Sound twekas for fastmenu: + rom.write_byte(0x6DD9A, 0x11) + rom.write_byte(0x6DF2A, 0x12) + rom.write_byte(0x6E0E9, 0x12) + + # enable quick item swapping with L and R (ported by Amazing Ampharos) + if quickswap: + rom.write_bytes(0x107fb, [0x22, 0x50, 0xFF, 0x1F]) + rom.write_bytes(0x12451, [0x22, 0x50, 0xFF, 0x1F]) + rom.write_bytes(0xfff50, [0x20, 0x58, 0xFF, 0xA5, 0xF6, 0x29, 0x40, 0x6B, 0xA5, 0xF6, 0x89, 0x10, 0xF0, 0x03, 0x4C, 0x69, + 0xFF, 0x89, 0x20, 0xF0, 0x03, 0x4C, 0xAA, 0xFF, 0x60, 0xAD, 0x02, 0x02, 0xF0, 0x3B, 0xDA, 0xAA, + 0xE0, 0x0F, 0xF0, 0x14, 0xE0, 0x10, 0xF0, 0x14, 0xE0, 0x14, 0xD0, 0x02, 0xA2, 0x00, 0xE8, 0xBF, + 0x3F, 0xF3, 0x7E, 0xF0, 0xEB, 0x4C, 0xEB, 0xFF, 0xA2, 0x01, 0x80, 0x0A, 0xAF, 0x4F, 0xF3, 0x7E, + 0xAA, 0xE0, 0x04, 0xF0, 0x10, 0xE8, 0xBF, 0x5B, 0xF3, 0x7E, 0xF0, 0xF5, 0x8A, 0x8F, 0x4F, 0xF3, + 0x7E, 0xA2, 0x10, 0x80, 0xE0, 0xA2, 0x11, 0x80, 0xD6, 0x60, 0xAD, 0x02, 0x02, 0xF0, 0x3B, 0xDA, + 0xAA, 0xE0, 0x11, 0xF0, 0x14, 0xE0, 0x10, 0xF0, 0x14, 0xE0, 0x01, 0xD0, 0x02, 0xA2, 0x15, 0xCA, + 0xBF, 0x3F, 0xF3, 0x7E, 0xF0, 0xEB, 0x4C, 0xEB, 0xFF, 0xA2, 0x04, 0x80, 0x0A, 0xAF, 0x4F, 0xF3, + 0x7E, 0xAA, 0xE0, 0x01, 0xF0, 0x10, 0xCA, 0xBF, 0x5B, 0xF3, 0x7E, 0xF0, 0xF5, 0x8A, 0x8F, 0x4F, + 0xF3, 0x7E, 0xA2, 0x10, 0x80, 0xE0, 0xA2, 0x0F, 0x80, 0xD6, 0x60, 0xA9, 0x20, 0x8D, 0x2F, 0x01, + 0x8E, 0x02, 0x02, 0x22, 0x7F, 0xDB, 0x0D, 0xFA, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) + else: + rom.write_bytes(0x107fb, [0xa5, 0xf6, 0x29, 0x40]) + rom.write_bytes(0x12451, [0xa5, 0xf6, 0x29, 0x40]) + rom.write_bytes(0xfff50, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) + + if disable_music: + volumeaddresses = [0xD373B, 0xD375B, 0xD90F8, 0xDA710, 0xDA7A4, 0xDA7BB, 0xDA7D2, 0xD5954, 0xD653B, 0xDA736, 0xDA752, 0xDA772, 0xDA792, + 0xD5B47, 0xD5B5E, 0xD4306, 0xD6878, 0xD6883, 0xD6E48, 0xD6E76, 0xD6EFB, 0xD6F2D, 0xDA211, 0xDA35B, 0xDA37B, 0xDA38E, + 0xDA39F, 0xDA5C3, 0xDA691, 0xDA6A8, 0xDA6DF, 0xD2349, 0xD3F45, 0xD42EB, 0xD48B9, 0xD48FF, 0xD543F, 0xD5817, 0xD5957, + 0xD5ACB, 0xD5AE8, 0xD5B4A, 0xDA5DE, 0xDA608, 0xDA635, 0xDA662, 0xDA71F, 0xDA7AF, 0xDA7C6, 0xDA7DD, 0xD2F00, 0xDA3D5, + 0xD249C, 0xD24CD, 0xD2C09, 0xD2C53, 0xD2CAF, 0xD2CEB, 0xD2D91, 0xD2EE6, 0xD38ED, 0xD3C91, 0xD3CD3, 0xD3CE8, 0xD3F0C, + 0xD3F82, 0xD405F, 0xD4139, 0xD4198, 0xD41D5, 0xD41F6, 0xD422B, 0xD4270, 0xD42B1, 0xD4334, 0xD4371, 0xD43A6, 0xD43DB, + 0xD441E, 0xD4597, 0xD4B3C, 0xD4BAB, 0xD4C03, 0xD4C53, 0xD4C7F, 0xD4D9C, 0xD5424, 0xD65D2, 0xD664F, 0xD6698, 0xD66FF, + 0xD6985, 0xD6C5C, 0xD6C6F, 0xD6C8E, 0xD6CB4, 0xD6D7D, 0xD827D, 0xD960C, 0xD9828, 0xDA233, 0xDA3A2, 0xDA49E, 0xDA72B, + 0xDA745, 0xDA765, 0xDA785, 0xDABF6, 0xDAC0D, 0xDAEBE, 0xDAFAC, 0xD9A02, 0xD9BD6, 0xD21CD, 0xD2279, 0xD2E66, 0xD2E70, + 0xD2EAB, 0xD3B97, 0xD3BAC, 0xD3BE8, 0xD3C0D, 0xD3C39, 0xD3C68, 0xD3C9F, 0xD3CBC, 0xD401E, 0xD4290, 0xD443E, 0xD456F, + 0xD47D3, 0xD4D43, 0xD4DCC, 0xD4EBA, 0xD4F0B, 0xD4FE5, 0xD5012, 0xD54BC, 0xD54D5, 0xD54F0, 0xD5509, 0xD57D8, 0xD59B9, + 0xD5A2F, 0xD5AEB, 0xD5E5E, 0xD5FE9, 0xD658F, 0xD674A, 0xD6827, 0xD69D6, 0xD69F5, 0xD6A05, 0xD6AE9, 0xD6DCF, 0xD6E20, + 0xD6ECB, 0xD71D4, 0xD71E6, 0xD7203, 0xD721E, 0xD8724, 0xD8732, 0xD9652, 0xD9698, 0xD9CBC, 0xD9DC0, 0xD9E49, 0xDAA68, + 0xDAA77, 0xDAA88, 0xDAA99, 0xDAF04, 0xD1D28, 0xD1D41, 0xD1D5C, 0xD1D77, 0xD1EEE, 0xD311D, 0xD31D1, 0xD4148, 0xD5543, + 0xD5B6F, 0xD65B3, 0xD6760, 0xD6B6B, 0xD6DF6, 0xD6E0D, 0xD73A1, 0xD814C, 0xD825D, 0xD82BE, 0xD8340, 0xD8394, 0xD842C, + 0xD8796, 0xD8903, 0xD892A, 0xD91E8, 0xD922B, 0xD92E0, 0xD937E, 0xD93C1, 0xDA958, 0xDA971, 0xDA98C, 0xDA9A7, 0xD1D92, + 0xD1DBD, 0xD1DEB, 0xD1F5D, 0xD1F9F, 0xD1FBD, 0xD1FDC, 0xD1FEA, 0xD20CA, 0xD21BB, 0xD22C9, 0xD2754, 0xD284C, 0xD2866, + 0xD2887, 0xD28A0, 0xD28BA, 0xD28DB, 0xD28F4, 0xD293E, 0xD2BF3, 0xD2C1F, 0xD2C69, 0xD2CA1, 0xD2CC5, 0xD2D05, 0xD2D73, + 0xD2DAF, 0xD2E3D, 0xD2F36, 0xD2F46, 0xD2F6F, 0xD2FCF, 0xD2FDF, 0xD302B, 0xD3086, 0xD3099, 0xD30A5, 0xD30CD, 0xD30F6, + 0xD3154, 0xD3184, 0xD333A, 0xD33D9, 0xD349F, 0xD354A, 0xD35E5, 0xD3624, 0xD363C, 0xD3672, 0xD3691, 0xD36B4, 0xD36C6, + 0xD3724, 0xD3767, 0xD38CB, 0xD3B1D, 0xD3B2F, 0xD3B55, 0xD3B70, 0xD3B81, 0xD3BBF, 0xD3D34, 0xD3D55, 0xD3D6E, 0xD3DC6, + 0xD3E04, 0xD3E38, 0xD3F65, 0xD3FA6, 0xD404F, 0xD4087, 0xD417A, 0xD41A0, 0xD425C, 0xD4319, 0xD433C, 0xD43EF, 0xD440C, + 0xD4452, 0xD4494, 0xD44B5, 0xD4512, 0xD45D1, 0xD45EF, 0xD4682, 0xD46C3, 0xD483C, 0xD4848, 0xD4855, 0xD4862, 0xD486F, + 0xD487C, 0xD4A1C, 0xD4A3B, 0xD4A60, 0xD4B27, 0xD4C7A, 0xD4D12, 0xD4D81, 0xD4E90, 0xD4ED6, 0xD4EE2, 0xD5005, 0xD502E, + 0xD503C, 0xD5081, 0xD51B1, 0xD51C7, 0xD51CF, 0xD51EF, 0xD520C, 0xD5214, 0xD5231, 0xD5257, 0xD526D, 0xD5275, 0xD52AF, + 0xD52BD, 0xD52CD, 0xD52DB, 0xD549C, 0xD5801, 0xD58A4, 0xD5A68, 0xD5A7F, 0xD5C12, 0xD5D71, 0xD5E10, 0xD5E9A, 0xD5F8B, + 0xD5FA4, 0xD651A, 0xD6542, 0xD65ED, 0xD661D, 0xD66D7, 0xD6776, 0xD68BD, 0xD68E5, 0xD6956, 0xD6973, 0xD69A8, 0xD6A51, + 0xD6A86, 0xD6B96, 0xD6C3E, 0xD6D4A, 0xD6E9C, 0xD6F80, 0xD717E, 0xD7190, 0xD71B9, 0xD811D, 0xD8139, 0xD816B, 0xD818A, + 0xD819E, 0xD81BE, 0xD829C, 0xD82E1, 0xD8306, 0xD830E, 0xD835E, 0xD83AB, 0xD83CA, 0xD83F0, 0xD83F8, 0xD844B, 0xD8479, + 0xD849E, 0xD84CB, 0xD84EB, 0xD84F3, 0xD854A, 0xD8573, 0xD859D, 0xD85B4, 0xD85CE, 0xD862A, 0xD8681, 0xD87E3, 0xD87FF, + 0xD887B, 0xD88C6, 0xD88E3, 0xD8944, 0xD897B, 0xD8C97, 0xD8CA4, 0xD8CB3, 0xD8CC2, 0xD8CD1, 0xD8D01, 0xD917B, 0xD918C, + 0xD919A, 0xD91B5, 0xD91D0, 0xD91DD, 0xD9220, 0xD9273, 0xD9284, 0xD9292, 0xD92AD, 0xD92C8, 0xD92D5, 0xD9311, 0xD9322, + 0xD9330, 0xD934B, 0xD9366, 0xD9373, 0xD93B6, 0xD97A6, 0xD97C2, 0xD97DC, 0xD97FB, 0xD9811, 0xD98FF, 0xD996F, 0xD99A8, + 0xD99D5, 0xD9A30, 0xD9A4E, 0xD9A6B, 0xD9A88, 0xD9AF7, 0xD9B1D, 0xD9B43, 0xD9B7C, 0xD9BA9, 0xD9C84, 0xD9C8D, 0xD9CAC, + 0xD9CE8, 0xD9CF3, 0xD9CFD, 0xD9D46, 0xDA35E, 0xDA37E, 0xDA391, 0xDA478, 0xDA4C3, 0xDA4D7, 0xDA4F6, 0xDA515, 0xDA6E2, + 0xDA9C2, 0xDA9ED, 0xDAA1B, 0xDAA57, 0xDABAF, 0xDABC9, 0xDABE2, 0xDAC28, 0xDAC46, 0xDAC63, 0xDACB8, 0xDACEC, 0xDAD08, + 0xDAD25, 0xDAD42, 0xDAD5F, 0xDAE17, 0xDAE34, 0xDAE51, 0xDAF2E, 0xDAF55, 0xDAF6B, 0xDAF81, 0xDB14F, 0xDB16B, 0xDB180, + 0xDB195, 0xDB1AA, 0xD2B88, 0xD364A, 0xD369F, 0xD3747, 0xD213F, 0xD2174, 0xD229E, 0xD2426, 0xD4731, 0xD4753, 0xD4774, + 0xD4795, 0xD47B6, 0xD4AA5, 0xD4AE4, 0xD4B96, 0xD4CA5, 0xD5477, 0xD5A3D, 0xD6566, 0xD672C, 0xD67C0, 0xD69B8, 0xD6AB1, + 0xD6C05, 0xD6DB3, 0xD71AB, 0xD8E2D, 0xD8F0D, 0xD94E0, 0xD9544, 0xD95A8, 0xD9982, 0xD9B56, 0xDA694, 0xDA6AB, 0xDAE88, + 0xDAEC8, 0xDAEE6, 0xDB1BF, 0xD210A, 0xD22DC, 0xD2447, 0xD5A4D, 0xD5DDC, 0xDA251, 0xDA26C, 0xD945E, 0xD967D, 0xD96C2, + 0xD9C95, 0xD9EE6, 0xDA5C6, 0xD2047, 0xD24C2, 0xD24EC, 0xD25A4, 0xD3DAA, 0xD51A8, 0xD51E6, 0xD524E, 0xD529E, 0xD6045, + 0xD81DE, 0xD821E, 0xD94AA, 0xD9A9E, 0xD9AE4, 0xDA289, 0xD2085, 0xD21C5, 0xD5F28] + for address in volumeaddresses: + rom.write_byte(address, 0x00) + else: + volumeaddresses1 = [0xD373B, 0xD375B, 0xD90F8] + for address in volumeaddresses1: + rom.write_byte(address, 0x00) + volumeaddresses2 = [0xDA710, 0xDA7A4, 0xDA7BB, 0xDA7D2] + for address in volumeaddresses2: + rom.write_byte(address, 0x14) + + volumeaddresses3 = [0xD5954, 0xD653B, 0xDA736, 0xDA752, 0xDA772, 0xDA792] + for address in volumeaddresses3: + rom.write_byte(address, 0x3C) + + volumeaddresses4 = [0xD5B47, 0xD5B5E] + for address in volumeaddresses4: + rom.write_byte(address, 0x50) + + rom.write_byte(0xD4306, 0x5A) + + volumeaddresses5 = [0xD6878, 0xD6883, 0xD6E48, 0xD6E76, 0xD6EFB, 0xD6F2D, 0xDA211, 0xDA35B, 0xDA37B, 0xDA38E, 0xDA39F, 0xDA5C3, 0xDA691, 0xDA6A8, 0xDA6DF] + for address in volumeaddresses5: + rom.write_byte(address, 0x64) + + volumeaddresses6 = [0xD2349, 0xD3F45, 0xD42EB, 0xD48B9, 0xD48FF, 0xD543F, 0xD5817, 0xD5957, 0xD5ACB, 0xD5AE8, 0xD5B4A, 0xDA5DE, 0xDA608, 0xDA635, + 0xDA662, 0xDA71F, 0xDA7AF, 0xDA7C6, 0xDA7DD] + for address in volumeaddresses6: + rom.write_byte(address, 0x78) + + volumeaddresses7 = [0xD2F00, 0xDA3D5] + for address in volumeaddresses7: + rom.write_byte(address, 0x82) + + volumeaddresses8 = [0xD249C, 0xD24CD, 0xD2C09, 0xD2C53, 0xD2CAF, 0xD2CEB, 0xD2D91, 0xD2EE6, 0xD38ED, 0xD3C91, 0xD3CD3, 0xD3CE8, 0xD3F0C, + 0xD3F82, 0xD405F, 0xD4139, 0xD4198, 0xD41D5, 0xD41F6, 0xD422B, 0xD4270, 0xD42B1, 0xD4334, 0xD4371, 0xD43A6, 0xD43DB, + 0xD441E, 0xD4597, 0xD4B3C, 0xD4BAB, 0xD4C03, 0xD4C53, 0xD4C7F, 0xD4D9C, 0xD5424, 0xD65D2, 0xD664F, 0xD6698, 0xD66FF, + 0xD6985, 0xD6C5C, 0xD6C6F, 0xD6C8E, 0xD6CB4, 0xD6D7D, 0xD827D, 0xD960C, 0xD9828, 0xDA233, 0xDA3A2, 0xDA49E, 0xDA72B, + 0xDA745, 0xDA765, 0xDA785, 0xDABF6, 0xDAC0D, 0xDAEBE, 0xDAFAC] + for address in volumeaddresses8: + rom.write_byte(address, 0xA0) + + volumeaddresses9 = [0xD9A02, 0xD9BD6] + for address in volumeaddresses9: + rom.write_byte(address, 0xAA) + + volumeaddressesA = [0xD21CD, 0xD2279, 0xD2E66, 0xD2E70, 0xD2EAB, 0xD3B97, 0xD3BAC, 0xD3BE8, 0xD3C0D, 0xD3C39, 0xD3C68, 0xD3C9F, 0xD3CBC, + 0xD401E, 0xD4290, 0xD443E, 0xD456F, 0xD47D3, 0xD4D43, 0xD4DCC, 0xD4EBA, 0xD4F0B, 0xD4FE5, 0xD5012, 0xD54BC, 0xD54D5, + 0xD54F0, 0xD5509, 0xD57D8, 0xD59B9, 0xD5A2F, 0xD5AEB, 0xD5E5E, 0xD5FE9, 0xD658F, 0xD674A, 0xD6827, 0xD69D6, 0xD69F5, + 0xD6A05, 0xD6AE9, 0xD6DCF, 0xD6E20, 0xD6ECB, 0xD71D4, 0xD71E6, 0xD7203, 0xD721E, 0xD8724, 0xD8732, 0xD9652, 0xD9698, + 0xD9CBC, 0xD9DC0, 0xD9E49, 0xDAA68, 0xDAA77, 0xDAA88, 0xDAA99, 0xDAF04] + for address in volumeaddressesA: + rom.write_byte(address, 0xB4) + + volumeaddressesB = [0xD1D28, 0xD1D41, 0xD1D5C, 0xD1D77, 0xD1EEE, 0xD311D, 0xD31D1, 0xD4148, 0xD5543, 0xD5B6F, 0xD65B3, 0xD6760, 0xD6B6B, + 0xD6DF6, 0xD6E0D, 0xD73A1, 0xD814C, 0xD825D, 0xD82BE, 0xD8340, 0xD8394, 0xD842C, 0xD8796, 0xD8903, 0xD892A, 0xD91E8, + 0xD922B, 0xD92E0, 0xD937E, 0xD93C1, 0xDA958, 0xDA971, 0xDA98C, 0xDA9A7] + for address in volumeaddressesB: + rom.write_byte(address, 0x8C) + + volumeaddressesC = [0xD1D92, 0xD1DBD, 0xD1DEB, 0xD1F5D, 0xD1F9F, 0xD1FBD, 0xD1FDC, 0xD1FEA, 0xD20CA, 0xD21BB, 0xD22C9, 0xD2754, 0xD284C, + 0xD2866, 0xD2887, 0xD28A0, 0xD28BA, 0xD28DB, 0xD28F4, 0xD293E, 0xD2BF3, 0xD2C1F, 0xD2C69, 0xD2CA1, 0xD2CC5, 0xD2D05, + 0xD2D73, 0xD2DAF, 0xD2E3D, 0xD2F36, 0xD2F46, 0xD2F6F, 0xD2FCF, 0xD2FDF, 0xD302B, 0xD3086, 0xD3099, 0xD30A5, 0xD30CD, + 0xD30F6, 0xD3154, 0xD3184, 0xD333A, 0xD33D9, 0xD349F, 0xD354A, 0xD35E5, 0xD3624, 0xD363C, 0xD3672, 0xD3691, 0xD36B4, + 0xD36C6, 0xD3724, 0xD3767, 0xD38CB, 0xD3B1D, 0xD3B2F, 0xD3B55, 0xD3B70, 0xD3B81, 0xD3BBF, 0xD3D34, 0xD3D55, 0xD3D6E, + 0xD3DC6, 0xD3E04, 0xD3E38, 0xD3F65, 0xD3FA6, 0xD404F, 0xD4087, 0xD417A, 0xD41A0, 0xD425C, 0xD4319, 0xD433C, 0xD43EF, + 0xD440C, 0xD4452, 0xD4494, 0xD44B5, 0xD4512, 0xD45D1, 0xD45EF, 0xD4682, 0xD46C3, 0xD483C, 0xD4848, 0xD4855, 0xD4862, + 0xD486F, 0xD487C, 0xD4A1C, 0xD4A3B, 0xD4A60, 0xD4B27, 0xD4C7A, 0xD4D12, 0xD4D81, 0xD4E90, 0xD4ED6, 0xD4EE2, 0xD5005, + 0xD502E, 0xD503C, 0xD5081, 0xD51B1, 0xD51C7, 0xD51CF, 0xD51EF, 0xD520C, 0xD5214, 0xD5231, 0xD5257, 0xD526D, 0xD5275, + 0xD52AF, 0xD52BD, 0xD52CD, 0xD52DB, 0xD549C, 0xD5801, 0xD58A4, 0xD5A68, 0xD5A7F, 0xD5C12, 0xD5D71, 0xD5E10, 0xD5E9A, + 0xD5F8B, 0xD5FA4, 0xD651A, 0xD6542, 0xD65ED, 0xD661D, 0xD66D7, 0xD6776, 0xD68BD, 0xD68E5, 0xD6956, 0xD6973, 0xD69A8, + 0xD6A51, 0xD6A86, 0xD6B96, 0xD6C3E, 0xD6D4A, 0xD6E9C, 0xD6F80, 0xD717E, 0xD7190, 0xD71B9, 0xD811D, 0xD8139, 0xD816B, + 0xD818A, 0xD819E, 0xD81BE, 0xD829C, 0xD82E1, 0xD8306, 0xD830E, 0xD835E, 0xD83AB, 0xD83CA, 0xD83F0, 0xD83F8, 0xD844B, + 0xD8479, 0xD849E, 0xD84CB, 0xD84EB, 0xD84F3, 0xD854A, 0xD8573, 0xD859D, 0xD85B4, 0xD85CE, 0xD862A, 0xD8681, 0xD87E3, + 0xD87FF, 0xD887B, 0xD88C6, 0xD88E3, 0xD8944, 0xD897B, 0xD8C97, 0xD8CA4, 0xD8CB3, 0xD8CC2, 0xD8CD1, 0xD8D01, 0xD917B, + 0xD918C, 0xD919A, 0xD91B5, 0xD91D0, 0xD91DD, 0xD9220, 0xD9273, 0xD9284, 0xD9292, 0xD92AD, 0xD92C8, 0xD92D5, 0xD9311, + 0xD9322, 0xD9330, 0xD934B, 0xD9366, 0xD9373, 0xD93B6, 0xD97A6, 0xD97C2, 0xD97DC, 0xD97FB, 0xD9811, 0xD98FF, 0xD996F, + 0xD99A8, 0xD99D5, 0xD9A30, 0xD9A4E, 0xD9A6B, 0xD9A88, 0xD9AF7, 0xD9B1D, 0xD9B43, 0xD9B7C, 0xD9BA9, 0xD9C84, 0xD9C8D, + 0xD9CAC, 0xD9CE8, 0xD9CF3, 0xD9CFD, 0xD9D46, 0xDA35E, 0xDA37E, 0xDA391, 0xDA478, 0xDA4C3, 0xDA4D7, 0xDA4F6, 0xDA515, + 0xDA6E2, 0xDA9C2, 0xDA9ED, 0xDAA1B, 0xDAA57, 0xDABAF, 0xDABC9, 0xDABE2, 0xDAC28, 0xDAC46, 0xDAC63, 0xDACB8, 0xDACEC, + 0xDAD08, 0xDAD25, 0xDAD42, 0xDAD5F, 0xDAE17, 0xDAE34, 0xDAE51, 0xDAF2E, 0xDAF55, 0xDAF6B, 0xDAF81, 0xDB14F, 0xDB16B, + 0xDB180, 0xDB195, 0xDB1AA] + for address in volumeaddressesC: + rom.write_byte(address, 0xC8) + + volumeaddressesD = [0xD2B88, 0xD364A, 0xD369F, 0xD3747] + for address in volumeaddressesD: + rom.write_byte(address, 0xD2) + + volumeaddressesE = [0xD213F, 0xD2174, 0xD229E, 0xD2426, 0xD4731, 0xD4753, 0xD4774, 0xD4795, 0xD47B6, 0xD4AA5, 0xD4AE4, 0xD4B96, 0xD4CA5, + 0xD5477, 0xD5A3D, 0xD6566, 0xD672C, 0xD67C0, 0xD69B8, 0xD6AB1, 0xD6C05, 0xD6DB3, 0xD71AB, 0xD8E2D, 0xD8F0D, 0xD94E0, + 0xD9544, 0xD95A8, 0xD9982, 0xD9B56, 0xDA694, 0xDA6AB, 0xDAE88, 0xDAEC8, 0xDAEE6, 0xDB1BF] + for address in volumeaddressesE: + rom.write_byte(address, 0xDC) + + volumeaddressesF = [0xD210A, 0xD22DC, 0xD2447, 0xD5A4D, 0xD5DDC, 0xDA251, 0xDA26C] + for address in volumeaddressesF: + rom.write_byte(address, 0xE6) + + volumeaddressesG = [0xD945E, 0xD967D, 0xD96C2, 0xD9C95, 0xD9EE6, 0xDA5C6] + for address in volumeaddressesG: + rom.write_byte(address, 0xF0) + + volumeaddressesH = [0xD2047, 0xD24C2, 0xD24EC, 0xD25A4, 0xD3DAA, 0xD51A8, 0xD51E6, 0xD524E, 0xD529E, 0xD6045, 0xD81DE, 0xD821E, 0xD94AA, + 0xD9A9E, 0xD9AE4, 0xDA289] + for address in volumeaddressesG: + rom.write_byte(address, 0xFA) + + volumeaddressesI = [0xD2085, 0xD21C5, 0xD5F28] + for address in volumeaddressesI: + rom.write_byte(address, 0xFF) + + + # set heart beep rate + rom.write_byte(0x180033, {'off': 0x00, 'half': 0x40, 'quarter': 0x80, 'normal': 0x20}[beep]) + + # write link sprite if required + if sprite is not None: + write_sprite(rom, sprite) + + if isinstance(rom, LocalRom): + rom.write_crc() + + return rom + +def adjust(args): + start = time.clock() + logger = logging.getLogger('') + logger.info('Patching ROM.') + + if args.sprite is not None: + sprite = bytearray(open(args.sprite, 'rb').read()) + else: + sprite = None + + outfilebase = 'ER_adjusted' + + rom = LocalRom(args.rom) + patch_rom(rom, args.fastmenu, args.quickswap, args.disablemusic, args.heartbeep, sprite) + + rom.write_to_file(output_path('%s.sfc' % outfilebase)) + + logger.info('Done. Enjoy.') + logger.debug('Total Time: %s' % (time.clock() - start)) + + return args \ No newline at end of file diff --git a/Gui.py b/Gui.py index 17214273..af631bc4 100644 --- a/Gui.py +++ b/Gui.py @@ -1,11 +1,12 @@ from Main import main, __version__ as ESVersion +from AdjusterMain import adjust from Utils import is_bundled, local_path, output_path, open_file from argparse import Namespace import random import subprocess import os import sys -from tkinter import Checkbutton, OptionMenu, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, Entry, Spinbox, Button, filedialog, messagebox, PhotoImage +from tkinter import Checkbutton, OptionMenu, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, Entry, Spinbox, Button, filedialog, messagebox, PhotoImage, ttk def guiMain(args=None): @@ -14,7 +15,14 @@ def guiMain(args=None): set_icon(mainWindow) - topFrame = Frame(mainWindow) + notebook = ttk.Notebook(mainWindow) + randomizerWindow = ttk.Frame(notebook) + adjustWindow = ttk.Frame(notebook) + notebook.add(randomizerWindow, text='Randomize') + notebook.add(adjustWindow, text='Adjust') + notebook.pack() + + topFrame = Frame(randomizerWindow) rightHalfFrame = Frame(topFrame) checkBoxFrame = Frame(rightHalfFrame) @@ -168,8 +176,8 @@ def guiMain(args=None): shuffleFrame.pack(expand=True, anchor=E) heartbeepFrame.pack(expand=True, anchor=E) - bottomFrame = Frame(mainWindow) - farBottomFrame = Frame(mainWindow) + bottomFrame = Frame(randomizerWindow) + farBottomFrame = Frame(randomizerWindow) seedLabel = Label(bottomFrame, text='Seed #') seedVar = StringVar() @@ -243,6 +251,96 @@ def guiMain(args=None): farBottomFrame.pack(side=BOTTOM, fill=X, padx=5, pady=5) bottomFrame.pack(side=BOTTOM) + topFrame2 = Frame(adjustWindow) + rightHalfFrame2 = Frame(topFrame2) + checkBoxFrame2 = Frame(rightHalfFrame2) + + quickSwapVar2 = IntVar() + quickSwapCheckbutton2 = Checkbutton(checkBoxFrame2, text="Enabled L/R Item quickswapping", variable=quickSwapVar2) + fastMenuVar2 = IntVar() + fastMenuCheckbutton2 = Checkbutton(checkBoxFrame2, text="Enable instant menu", variable=fastMenuVar2) + disableMusicVar2 = IntVar() + disableMusicCheckbutton2 = Checkbutton(checkBoxFrame2, text="Disable game music", variable=disableMusicVar2) + + quickSwapCheckbutton2.pack(expand=True, anchor=W) + fastMenuCheckbutton2.pack(expand=True, anchor=W) + disableMusicCheckbutton2.pack(expand=True, anchor=W) + + fileDialogFrame2 = Frame(rightHalfFrame2) + + romDialogFrame2 = Frame(fileDialogFrame2) + baseRomLabel2 = Label(romDialogFrame2, text='Rom to adjust') + romVar2 = StringVar() + romEntry2 = Entry(romDialogFrame2, textvariable=romVar2) + + def RomSelect2(): + rom = filedialog.askopenfilename() + romVar2.set(rom) + romSelectButton2 = Button(romDialogFrame2, text='Select Rom', command=RomSelect2) + + baseRomLabel2.pack(side=LEFT) + romEntry2.pack(side=LEFT) + romSelectButton2.pack(side=LEFT) + + spriteDialogFrame2 = Frame(fileDialogFrame2) + baseSpriteLabel2 = Label(spriteDialogFrame2, text='Link Sprite') + spriteVar2 = StringVar() + spriteEntry2 = Entry(spriteDialogFrame2, textvariable=spriteVar2) + + def SpriteSelect2(): + sprite = filedialog.askopenfilename() + spriteVar2.set(sprite) + + spriteSelectButton2 = Button(spriteDialogFrame2, text='Select Sprite', command=SpriteSelect2) + + baseSpriteLabel2.pack(side=LEFT) + spriteEntry2.pack(side=LEFT) + spriteSelectButton2.pack(side=LEFT) + + romDialogFrame2.pack() + spriteDialogFrame2.pack() + + checkBoxFrame2.pack() + fileDialogFrame2.pack() + + drowDownFrame2 = Frame(topFrame2) + + heartbeepFrame2 = Frame(drowDownFrame2) + heartbeepVar2 = StringVar() + heartbeepVar2.set('normal') + heartbeepOptionMenu2 = OptionMenu(heartbeepFrame2, heartbeepVar2, 'normal', 'half', 'quarter', 'off') + heartbeepOptionMenu2.pack(side=RIGHT) + heartbeepLabel2 = Label(heartbeepFrame2, text='Heartbeep sound rate') + heartbeepLabel2.pack(side=LEFT) + + heartbeepFrame2.pack(expand=True, anchor=E) + + bottomFrame2 = Frame(topFrame2) + + def adjustRom(): + guiargs = Namespace + guiargs.heartbeep = heartbeepVar2.get() + guiargs.fastmenu = bool(fastMenuVar2.get()) + guiargs.quickswap = bool(quickSwapVar2.get()) + guiargs.disablemusic = bool(disableMusicVar2.get()) + guiargs.rom = romVar2.get() + guiargs.sprite = spriteVar2.get() if spriteVar2.get() else None + try: + adjust(args=guiargs) + except Exception as e: + messagebox.showerror(title="Error while creating seed", message=str(e)) + else: + messagebox.showinfo(title="Success", message="Rom patched successfully") + + adjustButton = Button(bottomFrame2, text='Adjust Rom', command=adjustRom) + + adjustButton.pack(side=LEFT, padx=(5,0)) + + drowDownFrame2.pack(side=LEFT, pady=(0,40)) + rightHalfFrame2.pack(side=RIGHT) + topFrame2.pack(side=TOP, pady=30) + bottomFrame2.pack(side=BOTTOM, pady=(180,0)) + if args is not None: # load values from commandline args createSpoilerVar.set(int(args.create_spoiler))