diff --git a/Makefile b/Makefile index b2b6923..39b00e6 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ endif .PHONY: all clean clean_obj -all: $(TARGET_EXEC) assets/smw_assets.dat +all: $(TARGET_EXEC) smw_assets.dat $(TARGET_EXEC): $(OBJS) $(RES) $(CC) $^ -o $@ $(LDFLAGS) $(SDLFLAGS) @@ -28,7 +28,7 @@ $(TARGET_EXEC): $(OBJS) $(RES) # @echo "Generating Windows resources" # @$(WINDRES) $< -O coff -o $@ -assets/smw_assets.dat: +smw_assets.dat: @echo "Extracting game resources" $(PYTHON) assets/restool.py diff --git a/assets/restool.py b/assets/restool.py index a90fc80..3338210 100644 --- a/assets/restool.py +++ b/assets/restool.py @@ -7,13 +7,14 @@ parser.add_argument('-r', '--rom', nargs='?', metavar='ROM') parser.add_argument('--extract-from-rom', '-e', action='store_true', help='Extract assets from the ROM') parser.add_argument('--no-hash-check', '-f', action='store_true', help='Bypass the hash check (needed for Lunar Magic roms)') parser.add_argument('--no-include-rom', dest='include_rom', action='store_false', help='Don''t include the ROM in the assets file for verification') +parser.add_argument('--hack', dest='hack', help='Use the specified hack. Valid values: %s' % util.get_hack_variants()) optional = parser.add_argument_group('Debug things') optional.add_argument('--print-assets-header', action='store_true') args = parser.parse_args() -ROM = util.load_rom(args.rom, disable_hash_check = args.no_hash_check) +ROM = util.load_rom(args.rom, disable_hash_check = args.no_hash_check, rom_hack = args.hack) diff --git a/assets/util.py b/assets/util.py index b3304ca..fa13302 100644 --- a/assets/util.py +++ b/assets/util.py @@ -16,9 +16,9 @@ SMW_SHA1 = { SMW_SHA1_US : ('us', 'Super Mario World (USA)'), } -def load_rom(filename, support_multilanguage = False, disable_hash_check = False): +def load_rom(filename, disable_hash_check = False, rom_hack = None): global ROM - ROM = LoadedRom(filename, support_multilanguage, disable_hash_check) + ROM = LoadedRom(filename, disable_hash_check, rom_hack) return ROM def get_byte(addr): @@ -48,11 +48,48 @@ def get_int16(ea): def get_word(addr): return ROM.get_word(addr) +kHackInfo = { + 'enhanced' : ('Super Mario World Enhanced.ips', '2882a39ac64b597e9260e92aaba610d0b6f03adb', 'Super Mario World Enhanced.bsdiff', '5a53369916fd728033d16db3abceb487900f903a', 'ebe23d8a26759ba1b5c2f4d6d8f8db3ab88e902f'), + 'redrawn' : ('smw_redrawn.ips', '7168df51ba025a12177ce00e88540c1341ef3efc', 'smw_redrawn.bsdiff', '13b658e626020aa35dca4e1c3648c6a6d8afa901', '50702ffc8c2e7115c9ba0c80c8ec40da5a487651') +} +kModsPath = os.path.join(DEFAULT_ROM_DIRECTORY, '../smw_hacks/mods') + +def get_hack_variants(): + return ", ".join(kHackInfo.keys()) + +def get_hacked_variant(org_rom, hack): + if not os.path.exists(kModsPath): + raise Exception('\n\nERROR: You need to run: git clone https://github.com/snesrev/smw_hacks.git') + try: + import bsdiff4 + except: + raise Exception('\n\nERROR: You need to run pip install bsdiff4') + if hack not in kHackInfo: + raise Excepion(f'{hack} is not a valid hack variant. Valid values {get_hack_variants()}') + if hashlib.sha1(org_rom).hexdigest() != SMW_SHA1_US.lower(): + raise Exception(f'Input to the differ must be the original SMW rom with hash {SMW_SHA1_US}') + + ips_name, ips_hash, diff_name, diff_hash, patched_hash = kHackInfo[hack] + ips = open(os.path.join(kModsPath, ips_name), 'rb').read() + if hashlib.sha1(ips).hexdigest() != ips_hash: + raise Exception(f'{ips_name} has wrong hash. Expecting {ips_hash}') + + diff = open(os.path.join(kModsPath, diff_name), 'rb').read() + if hashlib.sha1(diff).hexdigest() != diff_hash: + raise Exception(f'{diff_name} has wrong hash. Expecting {diff_hash}') + patched = bsdiff4.patch(ips + org_rom, diff) + patched_hash_cur = hashlib.sha1(patched).hexdigest() + if patched_hash_cur != patched_hash: + raise Exception(f'Patched file has wrong hash. Expecting {patched_hash} got {patched_hash_cur}') + return patched class LoadedRom: - def __init__(self, path = None, support_multilanguage = False, disable_hash_check = False): - rom_path = self.__get_rom_path(path) - self.ROM = open(rom_path, 'rb').read() + def __init__(self, path = None, disable_hash_check = False, rom_hack = None): + self.ROM = open(self.__get_rom_path(path), 'rb').read() + + if rom_hack != None: + self.ROM = get_hacked_variant(self.ROM, rom_hack) + disable_hash_check = True # Remove the SMC header? if (len(self.ROM) & 0xfffff) == 0x200: