diff --git a/.gitignore b/.gitignore index ecd316cb75..1b54572f2f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ weights/ _persistent_storage.yaml mystery_result_*.yaml /db.db3 +*-errors.txt +success.txt diff --git a/Adjuster.py b/Adjuster.py index 794bd6c36f..661381a95d 100755 --- a/Adjuster.py +++ b/Adjuster.py @@ -65,7 +65,10 @@ def main(): logging.basicConfig(format='%(message)s', level=loglevel) args, path = adjust(args=args) from Utils import persistent_store - persistent_store("adjuster", "last_settings", args) + from Rom import Sprite + if isinstance(args.sprite, Sprite): + args.sprite = args.sprite.name + persistent_store("adjuster", "last_settings_3", args) if __name__ == '__main__': main() diff --git a/AdjusterMain.py b/AdjusterMain.py index 28a72d9cae..f26c669b69 100644 --- a/AdjusterMain.py +++ b/AdjusterMain.py @@ -27,7 +27,7 @@ def adjust(args): palettes_options['hud']=args.hud_palettes palettes_options['sword']=args.sword_palettes palettes_options['shield']=args.shield_palettes - palettes_options['link']=args.link_palettes + # palettes_options['link']=args.link_palettesvera apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, args.sprite, palettes_options) diff --git a/BaseClasses.py b/BaseClasses.py index b47e7e51c4..dd7b24e220 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -127,6 +127,7 @@ class World(object): set_player_attr('glitch_boots', True) set_player_attr('progression_balancing', True) set_player_attr('local_items', set()) + set_player_attr('non_local_items', set()) set_player_attr('triforce_pieces_available', 30) set_player_attr('triforce_pieces_required', 20) set_player_attr('shop_shuffle', 'off') diff --git a/Bosses.py b/Bosses.py index f4e7156a07..7d018c987e 100644 --- a/Bosses.py +++ b/Bosses.py @@ -123,7 +123,7 @@ def GanonDefeatRule(state, player: int): state.has('Silver Bow', player) and \ state.can_shoot_arrows(player) easy_hammer = state.world.difficulty_adjustments[player] == "easy" and state.has("Hammer", player) and \ - state.has('Silver Bow', player) and state.can_shoot_arrows(player) + state.has('Silver Bow', player) and state.can_shoot_arrows(player) can_hurt = state.has_beam_sword(player) or easy_hammer common = can_hurt and state.has_fire_source(player) # silverless ganon may be needed in minor glitches @@ -131,7 +131,7 @@ def GanonDefeatRule(state, player: int): # need to light torch a sufficient amount of times return common and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or ( state.has('Silver Bow', player) and state.can_shoot_arrows(player)) or - state.has('Lamp', player) or state.can_extend_magic(player, 12)) + state.has('Lamp', player) or state.can_extend_magic(player, 12)) else: return common and state.has('Silver Bow', player) and state.can_shoot_arrows(player) @@ -153,27 +153,33 @@ boss_table = { } -def can_place_boss(world, player: int, boss: str, dungeon_name: str, level: Optional[str] = None) -> bool: - if dungeon_name in ['Ganons Tower', 'Inverted Ganons Tower'] and level == 'top': - if boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]: +def can_place_boss(boss: str, dungeon_name: str, level: Optional[str] = None) -> bool: + #blacklist approach + if boss in {"Agahnim", "Agahnim2", "Ganon"}: + return False + + if dungeon_name == 'Ganons Tower': + if level == 'top': + if boss in {"Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"}: + return False + elif level == 'middle': + if boss == "Blind": + return False + + elif dungeon_name == 'Tower of Hera': + if boss in {"Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"}: return False - if dungeon_name in ['Ganons Tower', 'Inverted Ganons Tower'] and level == 'middle': - if boss in ["Blind"]: + elif dungeon_name == 'Skull Woods' : + if boss == "Trinexx": return False - if dungeon_name == 'Tower of Hera' and boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]: - return False - - if dungeon_name == 'Skull Woods' and boss in ["Trinexx"]: - return False - - if boss in ["Agahnim", "Agahnim2", "Ganon"]: - return False return True def place_boss(world, player: int, boss: str, location: str, level: Optional[str]): + if location == 'Ganons Tower' and world.mode[player] == 'inverted': + location = 'Inverted Ganons Tower' logging.debug('Placing boss %s at %s', boss, location + (' (' + level + ')' if level else '')) world.get_dungeon(location, player).bosses[level] = BossFactory(boss, player) @@ -182,43 +188,25 @@ def place_bosses(world, player: int): if world.boss_shuffle[player] == 'none': return # Most to least restrictive order - if world.mode[player] != 'inverted': - boss_locations = [ - ['Ganons Tower', 'top'], - ['Tower of Hera', None], - ['Skull Woods', None], - ['Ganons Tower', 'middle'], - ['Eastern Palace', None], - ['Desert Palace', None], - ['Palace of Darkness', None], - ['Swamp Palace', None], - ['Thieves Town', None], - ['Ice Palace', None], - ['Misery Mire', None], - ['Turtle Rock', None], - ['Ganons Tower', 'bottom'], - ] - else: - boss_locations = [ - ['Inverted Ganons Tower', 'top'], - ['Tower of Hera', None], - ['Skull Woods', None], - ['Inverted Ganons Tower', 'middle'], - ['Eastern Palace', None], - ['Desert Palace', None], - ['Palace of Darkness', None], - ['Swamp Palace', None], - ['Thieves Town', None], - ['Ice Palace', None], - ['Misery Mire', None], - ['Turtle Rock', None], - ['Inverted Ganons Tower', 'bottom'], - ] + boss_locations = [ + ['Ganons Tower', 'top'], + ['Tower of Hera', None], + ['Skull Woods', None], + ['Ganons Tower', 'middle'], + ['Eastern Palace', None], + ['Desert Palace', None], + ['Palace of Darkness', None], + ['Swamp Palace', None], + ['Thieves Town', None], + ['Ice Palace', None], + ['Misery Mire', None], + ['Turtle Rock', None], + ['Ganons Tower', 'bottom'], + ] all_bosses = sorted(boss_table.keys()) # sorted to be deterministic on older pythons placeable_bosses = [boss for boss in all_bosses if boss not in ['Agahnim', 'Agahnim2', 'Ganon']] - anywhere_bosses = [boss for boss in placeable_bosses if all( - can_place_boss(world, player, boss, loc, level) for loc, level in boss_locations)] + if world.boss_shuffle[player] in ["basic", "normal"]: if world.boss_shuffle[player] == "basic": # vanilla bosses shuffled bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm'] @@ -228,8 +216,8 @@ def place_bosses(world, player: int): logging.debug('Bosses chosen %s', bosses) world.random.shuffle(bosses) - for [loc, level] in boss_locations: - boss = next((b for b in bosses if can_place_boss(world, player, b, loc, level)), None) + for loc, level in boss_locations: + boss = next((b for b in bosses if can_place_boss(b, loc, level)), None) if not boss: loc_text = loc + (' (' + level + ')' if level else '') raise FillError('Could not place boss for location %s' % loc_text) @@ -237,10 +225,10 @@ def place_bosses(world, player: int): place_boss(world, player, boss, loc, level) elif world.boss_shuffle[player] == "chaos": # all bosses chosen at random - for [loc, level] in boss_locations: + for loc, level in boss_locations: try: boss = world.random.choice( - [b for b in placeable_bosses if can_place_boss(world, player, b, loc, level)]) + [b for b in placeable_bosses if can_place_boss(b, loc, level)]) except IndexError: loc_text = loc + (' (' + level + ')' if level else '') raise FillError('Could not place boss for location %s' % loc_text) @@ -252,14 +240,14 @@ def place_bosses(world, player: int): remaining_boss_locations = [] for loc, level in boss_locations: # place that boss where it can go - if can_place_boss(world, player, primary_boss, loc, level): + if can_place_boss(primary_boss, loc, level): place_boss(world, player, primary_boss, loc, level) else: remaining_boss_locations.append((loc, level)) if remaining_boss_locations: # pick a boss to go into the remaining locations remaining_boss = world.random.choice([boss for boss in placeable_bosses if all( - can_place_boss(world, player, boss, loc, level) for loc, level in remaining_boss_locations)]) + can_place_boss(boss, loc, level) for loc, level in remaining_boss_locations)]) for loc, level in remaining_boss_locations: place_boss(world, player, remaining_boss, loc, level) else: diff --git a/EntranceRandomizer.py b/EntranceRandomizer.py index 222c367c37..5c9ab56c34 100755 --- a/EntranceRandomizer.py +++ b/EntranceRandomizer.py @@ -181,7 +181,7 @@ def parse_arguments(argv, no_defaults=False): slightly biased to placing progression items with less restrictions. ''') - parser.add_argument('--shuffle', default=defval('full'), const='full', nargs='?', choices=['vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple'], + parser.add_argument('--shuffle', default=defval('vanilla'), const='vanilla', nargs='?', choices=['vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple'], help='''\ Select Entrance Shuffling Algorithm. (default: %(default)s) Full: Mix cave and dungeon entrances freely while limiting @@ -266,6 +266,8 @@ def parse_arguments(argv, no_defaults=False): help='Specifies a list of items that will be in your starting inventory (separated by commas)') parser.add_argument('--local_items', default=defval(''), help='Specifies a list of items that will not spread across the multiworld (separated by commas)') + parser.add_argument('--non_local_items', default=defval(''), + help='Specifies a list of items that will spread across the multiworld (separated by commas)') parser.add_argument('--custom', default=defval(False), help='Not supported.') parser.add_argument('--customitemarray', default=defval(False), help='Not supported.') parser.add_argument('--accessibility', default=defval('items'), const='items', nargs='?', choices=['items', 'locations', 'none'], help='''\ @@ -376,7 +378,7 @@ def parse_arguments(argv, no_defaults=False): 'shuffle', 'crystals_ganon', 'crystals_gt', 'open_pyramid', 'timer', 'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', - 'local_items', 'retro', 'accessibility', 'hints', 'beemizer', + 'local_items', 'non_local_items', 'retro', 'accessibility', 'hints', 'beemizer', 'shufflebosses', 'enemy_shuffle', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', "skip_progression_balancing", "triforce_pieces_available", diff --git a/Fill.py b/Fill.py index 9051f93a2b..1212f6e066 100644 --- a/Fill.py +++ b/Fill.py @@ -54,8 +54,9 @@ def fill_restrictive(world, base_state: CollectionState, locations, itempool, si for location in region.locations: if location.item and not location.event: placements.append(location) + raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. ' - f'Already placed {len(placements)}: {", ".join(placements)}') + f'Already placed {len(placements)}: {", ".join(str(place) for place in placements)}') world.push_item(spot_to_fill, item_to_place, False) locations.remove(spot_to_fill) diff --git a/Gui.py b/Gui.py index aa3a62206f..94a145abeb 100755 --- a/Gui.py +++ b/Gui.py @@ -34,7 +34,7 @@ def guiMain(args=None): customWindow = ttk.Frame(notebook) notebook.add(randomizerWindow, text='Randomize') notebook.add(adjustWindow, text='Adjust') - notebook.add(customWindow, text='Custom') + notebook.add(customWindow, text='Custom Items') notebook.pack() # Shared Controls @@ -96,8 +96,7 @@ def guiMain(args=None): hintsVar = IntVar() hintsVar.set(1) # set default hintsCheckbutton = Checkbutton(checkBoxFrame, text="Include Helpful Hints", variable=hintsVar) - customVar = IntVar() - customCheckbutton = Checkbutton(checkBoxFrame, text="Use custom item pool", variable=customVar) + balancingVar = IntVar() balancingVar.set(1) # set default balancingCheckbutton = Checkbutton(checkBoxFrame, text="Multiworld Progression Balancing", variable=balancingVar) @@ -116,60 +115,11 @@ def guiMain(args=None): retroCheckbutton.pack(expand=True, anchor=W) shuffleGanonCheckbutton.pack(expand=True, anchor=W) hintsCheckbutton.pack(expand=True, anchor=W) - customCheckbutton.pack(expand=True, anchor=W) + balancingCheckbutton.pack(expand=True, anchor=W) patchesCheckbutton.pack(expand=True, anchor=W) - - timerOptionsFrame = LabelFrame(rightHalfFrame, text="Timer options") - for i in range(3): - timerOptionsFrame.columnconfigure(i, weight=1) - timerOptionsFrame.rowconfigure(i, weight=1) - - timerModeFrame = Frame(timerOptionsFrame) - timerModeFrame.grid(row=0, column=0, columnspan=3, sticky=E, padx=3) - timerVar = StringVar() - timerVar.set('none') - timerModeMenu = OptionMenu(timerModeFrame, timerVar, 'none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown') - timerLabel = Label(timerModeFrame, text='Timer setting') - timerLabel.pack(side=LEFT) - timerModeMenu.pack(side=LEFT) - - timerCountdownFrame = Frame(timerOptionsFrame) - timerCountdownFrame.grid(row=1, column=0, columnspan=3, sticky=E, padx=3) - timerCountdownLabel = Label(timerCountdownFrame, text='Countdown starting time') - timerCountdownLabel.pack(side=LEFT) - timerCountdownVar = IntVar(value=10) - timerCountdownSpinbox = Spinbox(timerCountdownFrame, from_=0, to=480, width=3, textvariable=timerCountdownVar) - timerCountdownSpinbox.pack(side=LEFT) - - timerRedFrame = Frame(timerOptionsFrame) - timerRedFrame.grid(row=2, column=0, sticky=E, padx=3) - timerRedLabel = Label(timerRedFrame, text='Clock adjustments: Red') - timerRedLabel.pack(side=LEFT) - timerRedVar = IntVar(value=-2) - timerRedSpinbox = Spinbox(timerRedFrame, from_=-60, to=60, width=3, textvariable=timerRedVar) - timerRedSpinbox.pack(side=LEFT) - - timerBlueFrame = Frame(timerOptionsFrame) - timerBlueFrame.grid(row=2, column=1, sticky=E, padx=3) - timerBlueLabel = Label(timerBlueFrame, text='Blue') - timerBlueLabel.pack(side=LEFT) - timerBlueVar = IntVar(value=2) - timerBlueSpinbox = Spinbox(timerBlueFrame, from_=-60, to=60, width=3, textvariable=timerBlueVar) - timerBlueSpinbox.pack(side=LEFT) - - timerGreenFrame = Frame(timerOptionsFrame) - timerGreenFrame.grid(row=2, column=2, sticky=E, padx=3) - timerGreenLabel = Label(timerGreenFrame, text='Green') - timerGreenLabel.pack(side=LEFT) - timerGreenVar = IntVar(value=4) - timerGreenSpinbox = Spinbox(timerGreenFrame, from_=-60, to=60, width=3, textvariable=timerGreenVar) - timerGreenSpinbox.pack(side=LEFT) - - - romOptionsFrame = LabelFrame(rightHalfFrame, text="Rom options") romOptionsFrame.columnconfigure(0, weight=1) romOptionsFrame.columnconfigure(1, weight=1) @@ -316,7 +266,7 @@ def guiMain(args=None): romSelectButton.pack(side=LEFT) checkBoxFrame.pack(side=TOP, anchor=W, padx=5, pady=10) - timerOptionsFrame.pack(expand=True, fill=BOTH, padx=3) + romOptionsFrame.pack(expand=True, fill=BOTH, padx=3) drowDownFrame = Frame(topFrame) @@ -844,7 +794,10 @@ def guiMain(args=None): else: messagebox.showinfo(title="Success", message="Rom patched successfully") from Utils import persistent_store - persistent_store("adjuster", "last_settings", guiargs) + from 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) @@ -866,12 +819,65 @@ def guiMain(args=None): return False vcmd=(topFrame3.register(validation), '%P') + timerOptionsFrame = LabelFrame(topFrame3, text="Timer options") + for i in range(3): + timerOptionsFrame.columnconfigure(i, weight=1) + timerOptionsFrame.rowconfigure(i, weight=1) + + timerModeFrame = Frame(timerOptionsFrame) + timerModeFrame.grid(row=0, column=0, columnspan=3, sticky=E, padx=3) + timerVar = StringVar() + timerVar.set('none') + timerModeMenu = OptionMenu(timerModeFrame, timerVar, 'none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown') + timerLabel = Label(timerModeFrame, text='Timer setting') + timerLabel.pack(side=LEFT) + timerModeMenu.pack(side=LEFT) + + timerCountdownFrame = Frame(timerOptionsFrame) + timerCountdownFrame.grid(row=1, column=0, columnspan=3, sticky=E, padx=3) + timerCountdownLabel = Label(timerCountdownFrame, text='Countdown starting time') + timerCountdownLabel.pack(side=LEFT) + timerCountdownVar = IntVar(value=10) + timerCountdownSpinbox = Spinbox(timerCountdownFrame, from_=0, to=480, width=3, textvariable=timerCountdownVar) + timerCountdownSpinbox.pack(side=LEFT) + + timerRedFrame = Frame(timerOptionsFrame) + timerRedFrame.grid(row=2, column=0, sticky=E, padx=3) + timerRedLabel = Label(timerRedFrame, text='Clock adjustments: Red') + timerRedLabel.pack(side=LEFT) + timerRedVar = IntVar(value=-2) + timerRedSpinbox = Spinbox(timerRedFrame, from_=-60, to=60, width=3, textvariable=timerRedVar) + timerRedSpinbox.pack(side=LEFT) + + timerBlueFrame = Frame(timerOptionsFrame) + timerBlueFrame.grid(row=2, column=1, sticky=E, padx=3) + timerBlueLabel = Label(timerBlueFrame, text='Blue') + timerBlueLabel.pack(side=LEFT) + timerBlueVar = IntVar(value=2) + timerBlueSpinbox = Spinbox(timerBlueFrame, from_=-60, to=60, width=3, textvariable=timerBlueVar) + timerBlueSpinbox.pack(side=LEFT) + + timerGreenFrame = Frame(timerOptionsFrame) + timerGreenFrame.grid(row=2, column=2, sticky=E, padx=3) + timerGreenLabel = Label(timerGreenFrame, text='Green') + timerGreenLabel.pack(side=LEFT) + timerGreenVar = IntVar(value=4) + timerGreenSpinbox = Spinbox(timerGreenFrame, from_=-60, to=60, width=3, textvariable=timerGreenVar) + timerGreenSpinbox.pack(side=LEFT) + + timerOptionsFrame.pack(expand=True, fill=BOTH, padx=3) + + itemList1 = Frame(topFrame3) itemList2 = Frame(topFrame3) itemList3 = Frame(topFrame3) itemList4 = Frame(topFrame3) itemList5 = Frame(topFrame3) + customVar = IntVar() + customCheckbutton = Checkbutton(topFrame3, text="Use custom item pool", variable=customVar) + customCheckbutton.pack(expand=True, anchor=W) + bowFrame = Frame(itemList1) bowLabel = Label(bowFrame, text='Bow') bowVar = StringVar(value='0') @@ -1492,7 +1498,8 @@ def guiMain(args=None): mainWindow.mainloop() -class SpriteSelector(object): + +class SpriteSelector(): def __init__(self, parent, callback, adjuster=False): if is_bundled(): self.deploy_icons() @@ -1615,93 +1622,15 @@ class SpriteSelector(object): self.window.destroy() self.parent.update() - def work(task): - resultmessage = "" - successful = True - - def finished(): - task.close_window() - if successful: - messagebox.showinfo("Sprite Updater", resultmessage) - else: - messagebox.showerror("Sprite Updater", resultmessage) - SpriteSelector(self.parent, self.callback, self.adjuster) - - try: - task.update_status("Downloading alttpr sprites list") - with urlopen('https://alttpr.com/sprites') as response: - sprites_arr = json.loads(response.read().decode("utf-8")) - except Exception as e: - resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) - successful = False - task.queue_event(finished) - return - - try: - task.update_status("Determining needed sprites") - current_sprites = [os.path.basename(file) for file in glob(self.alttpr_sprite_dir + '/*')] - alttpr_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr] - needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in alttpr_sprites if filename not in current_sprites] - - alttpr_filenames = [filename for (_, filename) in alttpr_sprites] - obsolete_sprites = [sprite for sprite in current_sprites if sprite not in alttpr_filenames] - except Exception as e: - resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) - successful = False - task.queue_event(finished) - return - - - def dl(sprite_url, filename): - target = os.path.join(self.alttpr_sprite_dir, filename) - with urlopen(sprite_url) as response, open(target, 'wb') as out: - shutil.copyfileobj(response, out) - - def rem(sprite): - os.remove(os.path.join(self.alttpr_sprite_dir, sprite)) - - - with ThreadPoolExecutor() as pool: - dl_tasks = [] - rem_tasks = [] - - for (sprite_url, filename) in needed_sprites: - dl_tasks.append(pool.submit(dl, sprite_url, filename)) - - for sprite in obsolete_sprites: - rem_tasks.append(pool.submit(rem, sprite)) - - deleted = 0 - updated = 0 - - for dl_task in as_completed(dl_tasks): - updated += 1 - task.update_status("Downloading needed sprite %g/%g" % (updated, len(needed_sprites))) - try: - dl_task.result() - except Exception as e: - logging.exception(e) - resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % ( - type(e).__name__, e) - successful = False - - for rem_task in as_completed(rem_tasks): - deleted += 1 - task.update_status("Removing obsolete sprite %g/%g" % (deleted, len(obsolete_sprites))) - try: - rem_task.result() - except Exception as e: - logging.exception(e) - resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % ( - type(e).__name__, e) - successful = False - + def on_finish(successful, resultmessage): if successful: - resultmessage = "alttpr sprites updated successfully" + messagebox.showinfo("Sprite Updater", resultmessage) + else: + logging.error(resultmessage) + messagebox.showerror("Sprite Updater", resultmessage) + SpriteSelector(self.parent, self.callback, self.adjuster) - task.queue_event(finished) - - BackgroundTaskProgress(self.parent, work, "Updating Sprites") + BackgroundTaskProgress(self.parent, update_sprites, "Updating Sprites", on_finish) def browse_for_sprite(self): @@ -1745,34 +1674,104 @@ class SpriteSelector(object): self.callback(spritename) self.window.destroy() - def deploy_icons(self): if not os.path.exists(self.custom_sprite_dir): os.makedirs(self.custom_sprite_dir) - if not os.path.exists(self.alttpr_sprite_dir): - shutil.copytree(self.local_alttpr_sprite_dir, self.alttpr_sprite_dir) @property def alttpr_sprite_dir(self): - if is_bundled(): - return output_path("sprites", "alttpr") - return self.local_alttpr_sprite_dir - - @property - def local_alttpr_sprite_dir(self): return local_path("data", "sprites", "alttpr") @property def custom_sprite_dir(self): - if is_bundled(): - return output_path("sprites", "custom") - return self.local_custom_sprite_dir - - @property - def local_custom_sprite_dir(self): return local_path("data", "sprites", "custom") +def update_sprites(task, on_finish=None): + resultmessage = "" + successful = True + sprite_dir = local_path("data", "sprites", "alttpr") + os.makedirs(sprite_dir, exist_ok=True) + + def finished(): + task.close_window() + if on_finish: + on_finish(successful, resultmessage) + + try: + task.update_status("Downloading alttpr sprites list") + with urlopen('https://alttpr.com/sprites') as response: + sprites_arr = json.loads(response.read().decode("utf-8")) + except Exception as e: + resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) + successful = False + task.queue_event(finished) + return + + try: + task.update_status("Determining needed sprites") + current_sprites = [os.path.basename(file) for file in glob(sprite_dir + '/*')] + alttpr_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr] + needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in alttpr_sprites if filename not in current_sprites] + + alttpr_filenames = [filename for (_, filename) in alttpr_sprites] + obsolete_sprites = [sprite for sprite in current_sprites if sprite not in alttpr_filenames] + except Exception as e: + resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) + successful = False + task.queue_event(finished) + return + + + def dl(sprite_url, filename): + target = os.path.join(sprite_dir, filename) + with urlopen(sprite_url) as response, open(target, 'wb') as out: + shutil.copyfileobj(response, out) + + def rem(sprite): + os.remove(os.path.join(sprite_dir, sprite)) + + + with ThreadPoolExecutor() as pool: + dl_tasks = [] + rem_tasks = [] + + for (sprite_url, filename) in needed_sprites: + dl_tasks.append(pool.submit(dl, sprite_url, filename)) + + for sprite in obsolete_sprites: + rem_tasks.append(pool.submit(rem, sprite)) + + deleted = 0 + updated = 0 + + for dl_task in as_completed(dl_tasks): + updated += 1 + task.update_status("Downloading needed sprite %g/%g" % (updated, len(needed_sprites))) + try: + dl_task.result() + except Exception as e: + logging.exception(e) + resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % ( + type(e).__name__, e) + successful = False + + for rem_task in as_completed(rem_tasks): + deleted += 1 + task.update_status("Removing obsolete sprite %g/%g" % (deleted, len(obsolete_sprites))) + try: + rem_task.result() + except Exception as e: + logging.exception(e) + resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % ( + type(e).__name__, e) + successful = False + + if successful: + resultmessage = "alttpr sprites updated successfully" + + task.queue_event(finished) + def get_image_for_sprite(sprite, gif_only: bool = False): if not sprite.valid: return None @@ -1877,5 +1876,16 @@ def get_image_for_sprite(sprite, gif_only: bool = False): return image.zoom(2) if __name__ == '__main__': - logging.basicConfig(format='%(message)s', level=logging.INFO) - guiMain() + import sys + if "update_sprites" in sys.argv: + 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") + else: + logging.basicConfig(format='%(message)s', level=logging.INFO) + guiMain() diff --git a/GuiUtils.py b/GuiUtils.py index 0bebfda619..c054207691 100644 --- a/GuiUtils.py +++ b/GuiUtils.py @@ -14,12 +14,12 @@ def set_icon(window): # some which may be platform specific, or depend on if the TCL library was compiled without # multithreading support. Therefore I will assume it is not thread safe to avoid any possible problems class BackgroundTask(object): - def __init__(self, window, code_to_run): + def __init__(self, window, code_to_run, *args): self.window = window self.queue = queue.Queue() self.running = True self.process_queue() - self.task = threading.Thread(target=code_to_run, args=(self,)) + self.task = threading.Thread(target=code_to_run, args=(self, *args)) self.task.start() def stop(self): @@ -45,7 +45,7 @@ class BackgroundTask(object): self.window.after(100, self.process_queue) class BackgroundTaskProgress(BackgroundTask): - def __init__(self, parent, code_to_run, title): + def __init__(self, parent, code_to_run, title, *args): self.parent = parent self.window = tk.Toplevel(parent) self.window['padx'] = 5 @@ -65,7 +65,7 @@ class BackgroundTaskProgress(BackgroundTask): set_icon(self.window) self.window.focus() - super().__init__(self.window, code_to_run) + super().__init__(self.window, code_to_run, *args) #safe to call from worker thread def update_status(self, text): diff --git a/Main.py b/Main.py index 84f449fc2e..e58dcdafa9 100644 --- a/Main.py +++ b/Main.py @@ -10,7 +10,7 @@ import zlib import concurrent.futures from BaseClasses import World, CollectionState, Item, Region, Location, Shop -from Items import ItemFactory +from Items import ItemFactory, item_table from Regions import create_regions, create_shops, mark_light_world_regions, lookup_vanilla_location_to_entrance from InvertedRegions import create_inverted_regions, mark_dark_world_regions from EntranceShuffle import link_entrances, link_inverted_entrances @@ -110,7 +110,13 @@ def main(args, seed=None): item = ItemFactory(tok.strip(), player) if item: world.push_precollected(item) - world.local_items[player] = {item.strip() for item in args.local_items[player].split(',')} + # item in item_table gets checked in mystery, but not CLI - so we double-check here + world.local_items[player] = {item.strip() for item in args.local_items[player].split(',') if + item.strip() in item_table} + world.non_local_items[player] = {item.strip() for item in args.non_local_items[player].split(',') if + item.strip() in item_table} + # items can't be both local and non-local, prefer local + world.non_local_items[player] -= world.local_items[player] world.triforce_pieces_available[player] = max(world.triforce_pieces_available[player], world.triforce_pieces_required[player]) diff --git a/MultiClient.py b/MultiClient.py index 22134dc9aa..3c98708cb6 100644 --- a/MultiClient.py +++ b/MultiClient.py @@ -73,7 +73,6 @@ class Context(): self.snes_reconnect_address = None self.snes_recv_queue = asyncio.Queue() self.snes_request_lock = asyncio.Lock() - self.is_sd2snes = False self.snes_write_buffer = [] self.server_task = None @@ -522,15 +521,6 @@ async def snes_connect(ctx: Context, address): ctx.snes_attached_device = (devices.index(device), device) ctx.ui_node.send_connection_status(ctx) - if 'sd2snes' in device.lower() or (len(device) == 4 and device[:3] == 'COM'): - ctx.ui_node.log_info("SD2SNES Detected") - ctx.is_sd2snes = True - await ctx.snes_socket.send(json.dumps({"Opcode" : "Info", "Space" : "SNES"})) - reply = json.loads(await ctx.snes_socket.recv()) - if reply and 'Results' in reply: - ctx.ui_node.log_info(reply['Results']) - else: - ctx.is_sd2snes = False ctx.snes_reconnect_address = address recv_task = asyncio.create_task(snes_recv_loop(ctx)) @@ -645,47 +635,19 @@ async def snes_write(ctx : Context, write_list): if ctx.snes_state != SNES_ATTACHED or ctx.snes_socket is None or not ctx.snes_socket.open or ctx.snes_socket.closed: return False - PutAddress_Request = { - "Opcode" : "PutAddress", - "Operands" : [] - } - - if ctx.is_sd2snes: - cmd = b'\x00\xE2\x20\x48\xEB\x48' + PutAddress_Request = {"Opcode": "PutAddress", "Operands": [], 'Space': 'SNES'} + try: + #will pack those requests as soon as qusb2snes actually supports that for real for address, data in write_list: - if (address < WRAM_START) or ((address + len(data)) > (WRAM_START + WRAM_SIZE)): - ctx.ui_node.log_error("SD2SNES: Write out of range %s (%d)" % (hex(address), len(data))) - return False - for ptr, byte in enumerate(data, address + 0x7E0000 - WRAM_START): - cmd += b'\xA9' # LDA - cmd += bytes([byte]) - cmd += b'\x8F' # STA.l - cmd += bytes([ptr & 0xFF, (ptr >> 8) & 0xFF, (ptr >> 16) & 0xFF]) - - cmd += b'\xA9\x00\x8F\x00\x2C\x00\x68\xEB\x68\x28\x6C\xEA\xFF\x08' - - PutAddress_Request['Space'] = 'CMD' - PutAddress_Request['Operands'] = ["2C00", hex(len(cmd)-1)[2:], "2C00", "1"] - try: + PutAddress_Request['Operands'] = [hex(address)[2:], hex(len(data))[2:]] if ctx.snes_socket is not None: await ctx.snes_socket.send(json.dumps(PutAddress_Request)) if ctx.snes_socket is not None: - await ctx.snes_socket.send(cmd) - except websockets.ConnectionClosed: - return False - else: - PutAddress_Request['Space'] = 'SNES' - try: - #will pack those requests as soon as qusb2snes actually supports that for real - for address, data in write_list: - PutAddress_Request['Operands'] = [hex(address)[2:], hex(len(data))[2:]] - if ctx.snes_socket is not None: - await ctx.snes_socket.send(json.dumps(PutAddress_Request)) - if ctx.snes_socket is not None: - await ctx.snes_socket.send(data) - except websockets.ConnectionClosed: - return False + await ctx.snes_socket.send(data) + except websockets.ConnectionClosed: + logging.warning("Could not write data to SNES") + return False return True finally: @@ -811,8 +773,8 @@ async def process_server_cmd(ctx: Context, cmd, args): if args['password']: ctx.ui_node.log_info('Password required') if "forfeit_mode" in args: # could also be version > 2.2.1, but going with implicit content here - logging.info("Forfeit setting: "+args["forfeit_mode"]) - logging.info("Remaining setting: "+args["remaining_mode"]) + logging.info(f"Forfeit setting: {args['forfeit_mode']}") + logging.info(f"Remaining setting: {args['remaining_mode']}") logging.info(f"A !hint costs {args['hint_cost']} points and you get {args['location_check_points']}" f" for each location checked.") ctx.hint_cost = int(args['hint_cost']) diff --git a/MultiMystery.py b/MultiMystery.py index e51ba53413..bc84dd570f 100644 --- a/MultiMystery.py +++ b/MultiMystery.py @@ -1,4 +1,4 @@ -__author__ = "Berserker55" # you can find me on the ALTTP Randomizer Discord +__author__ = "Berserker55" # you can find me on discord.gg/8Z65BR2 """ This script launches a Multiplayer "Multiworld" Mystery Game @@ -18,16 +18,18 @@ import sys import threading import concurrent.futures import argparse +import logging def feedback(text: str): - print(text) + logging.info(text) input("Press Enter to ignore and probably crash.") if __name__ == "__main__": + logging.basicConfig(format='%(message)s', level=logging.INFO) try: - print(f"{__author__}'s MultiMystery Launcher") + logging.info(f"{__author__}'s MultiMystery Launcher") import ModuleUpdate ModuleUpdate.update() @@ -46,6 +48,7 @@ if __name__ == "__main__": output_path = options["general_options"]["output_path"] enemizer_path = multi_mystery_options["enemizer_path"] player_files_path = multi_mystery_options["player_files_path"] + target_player_count = multi_mystery_options["players"] race = multi_mystery_options["race"] create_spoiler = multi_mystery_options["create_spoiler"] zip_roms = multi_mystery_options["zip_roms"] @@ -53,47 +56,53 @@ if __name__ == "__main__": zip_spoiler = multi_mystery_options["zip_spoiler"] zip_multidata = multi_mystery_options["zip_multidata"] zip_format = multi_mystery_options["zip_format"] - #zip_password = multi_mystery_options["zip_password"] not at this time + # zip_password = multi_mystery_options["zip_password"] not at this time player_name = multi_mystery_options["player_name"] meta_file_path = multi_mystery_options["meta_file_path"] + weights_file_path = multi_mystery_options["weights_file_path"] teams = multi_mystery_options["teams"] rom_file = options["general_options"]["rom_file"] host = options["server_options"]["host"] port = options["server_options"]["port"] - py_version = f"{sys.version_info.major}.{sys.version_info.minor}" if not os.path.exists(enemizer_path): - feedback(f"Enemizer not found at {enemizer_path}, please adjust the path in MultiMystery.py's config or put Enemizer in the default location.") + feedback( + f"Enemizer not found at {enemizer_path}, please adjust the path in MultiMystery.py's config or put Enemizer in the default location.") if not os.path.exists(rom_file): feedback(f"Base rom is expected as {rom_file} in the Multiworld root folder please place/rename it there.") player_files = [] os.makedirs(player_files_path, exist_ok=True) for file in os.listdir(player_files_path): lfile = file.lower() - if lfile.endswith(".yaml") and lfile != meta_file_path.lower(): + if lfile.endswith(".yaml") and lfile != meta_file_path.lower() and lfile != weights_file_path.lower(): player_files.append(file) - print(f"Found player's file {file}.") - player_count = len(player_files) - if player_count == 0: - feedback(f"No player files found. Please put them in a {player_files_path} folder.") - else: - print(player_count, "Players found.") + logging.info(f"Found player's file {file}.") player_string = "" for i, file in enumerate(player_files, 1): player_string += f"--p{i} \"{os.path.join(player_files_path, file)}\" " - if os.path.exists("BerserkerMultiServer.exe"): - basemysterycommand = "BerserkerMystery.exe" #compiled windows + basemysterycommand = "BerserkerMystery.exe" # compiled windows elif os.path.exists("BerserkerMultiServer"): - basemysterycommand = "BerserkerMystery" # compiled linux + basemysterycommand = "BerserkerMystery" # compiled linux else: basemysterycommand = f"py -{py_version} Mystery.py" # source - command = f"{basemysterycommand} --multi {len(player_files)} {player_string} " \ + weights_file_path = os.path.join(player_files_path, weights_file_path) + if os.path.exists(weights_file_path): + target_player_count = max(len(player_files), target_player_count) + else: + target_player_count = len(player_files) + + if target_player_count == 0: + feedback(f"No player files found. Please put them in a {player_files_path} folder.") + else: + logging.info(f"{target_player_count} Players found.") + + command = f"{basemysterycommand} --multi {target_player_count} {player_string} " \ f"--rom \"{rom_file}\" --enemizercli \"{enemizer_path}\" " \ f"--outputpath \"{output_path}\" --teams {teams}" @@ -107,13 +116,15 @@ if __name__ == "__main__": command += " --race" if os.path.exists(os.path.join(player_files_path, meta_file_path)): command += f" --meta {os.path.join(player_files_path, meta_file_path)}" + if os.path.exists(weights_file_path): + command += f" --weights {weights_file_path}" - print(command) + logging.info(command) import time start = time.perf_counter() text = subprocess.check_output(command, shell=True).decode() - print(f"Took {time.perf_counter() - start:.3f} seconds to generate multiworld.") + logging.info(f"Took {time.perf_counter() - start:.3f} seconds to generate multiworld.") seedname = "" for segment in text.split(): @@ -136,9 +147,10 @@ if __name__ == "__main__": if any((zip_roms, zip_multidata, zip_spoiler, zip_diffs)): import zipfile - compression = {1 : zipfile.ZIP_DEFLATED, - 2 : zipfile.ZIP_LZMA, - 3 : zipfile.ZIP_BZIP2}[zip_format] + + compression = {1: zipfile.ZIP_DEFLATED, + 2: zipfile.ZIP_LZMA, + 3: zipfile.ZIP_BZIP2}[zip_format] typical_zip_ending = {1: "zip", 2: "7z", @@ -150,17 +162,17 @@ if __name__ == "__main__": def pack_file(file: str): with ziplock: zf.write(os.path.join(output_path, file), file) - print(f"Packed {file} into zipfile {zipname}") + logging.info(f"Packed {file} into zipfile {zipname}") def remove_zipped_file(file: str): os.remove(os.path.join(output_path, file)) - print(f"Removed {file} which is now present in the zipfile") + logging.info(f"Removed {file} which is now present in the zipfile") zipname = os.path.join(output_path, f"BM_{seedname}.{typical_zip_ending}") - print(f"Creating zipfile {zipname}") + logging.info(f"Creating zipfile {zipname}") ipv4 = (host if host else get_public_ipv4()) + ":" + str(port) @@ -209,10 +221,11 @@ if __name__ == "__main__": baseservercommand = "BerserkerMultiServer" # compiled linux else: baseservercommand = f"py -{py_version} MultiServer.py" # source - #don't have a mac to test that. If you try to run compiled on mac, good luck. + # don't have a mac to test that. If you try to run compiled on mac, good luck. subprocess.call(f"{baseservercommand} --multidata {os.path.join(output_path, multidataname)}") except: import traceback + traceback.print_exc() input("Press enter to close") diff --git a/MultiServer.py b/MultiServer.py index 7f97cdd612..5503a61cda 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -58,6 +58,15 @@ class Client(Endpoint): class Context(Node): + simple_options = {"hint_cost": int, + "location_check_points": int, + "server_password": str, + "password": str, + "forfeit_mode": str, + "remaining_mode": str, + "item_cheat": bool, + "compatibility": int} + def __init__(self, host: str, port: int, server_password: str, password: str, location_check_points: int, hint_cost: int, item_cheat: bool, forfeit_mode: str = "disabled", remaining_mode: str = "disabled", auto_shutdown: typing.SupportsFloat = 0, compatibility: int = 2): @@ -131,15 +140,23 @@ class Context(Node): self._set_options(server_options) def _set_options(self, server_options: dict): - - sentinel = object() for key, value in server_options.items(): - if key not in self.embedded_blacklist: - current = getattr(self, key, sentinel) - if current is not sentinel: - logging.debug(f"Setting server option {key} to {value} from supplied multidata") - setattr(self, key, value) - self.item_cheat = not server_options.get("disable_item_cheat", True) + data_type = self.simple_options.get(key, None) + if data_type is not None: + if value not in {False, True, None}: # some can be boolean OR text, such as password + try: + value = data_type(value) + except Exception as e: + try: + raise Exception(f"Could not set server option {key}, skipping.") from e + except Exception as e: + logging.exception(e) + logging.debug(f"Setting server option {key} to {value} from supplied multidata") + setattr(self, key, value) + elif key == "disable_item_cheat": + self.item_cheat = not bool(value) + else: + logging.debug(f"Unrecognized server option {key}") def save(self, now=False) -> bool: if self.saving: @@ -651,15 +668,6 @@ class CommandProcessor(metaclass=CommandMeta): class CommonCommandProcessor(CommandProcessor): ctx: Context - simple_options = {"hint_cost": int, - "location_check_points": int, - "server_password": str, - "password": str, - "forfeit_mode": str, - "item_cheat": bool, - "auto_save_interval": int, - "compatibility": int} - def _cmd_countdown(self, seconds: str = "10") -> bool: """Start a countdown in seconds""" try: @@ -672,7 +680,7 @@ class CommonCommandProcessor(CommandProcessor): def _cmd_options(self): """List all current options. Warning: lists password.""" self.output("Current options:") - for option in self.simple_options: + for option in self.ctx.simple_options: if option == "server_password" and self.marker == "!": #Do not display the server password to the client. self.output(f"Option server_password is set to {('*' * random.randint(4,16))}") else: @@ -1231,7 +1239,7 @@ class ServerCommandProcessor(CommonCommandProcessor): def _cmd_option(self, option_name: str, option: str): """Set options for the server. Warning: expires on restart""" - attrtype = self.simple_options.get(option_name, None) + attrtype = self.ctx.simple_options.get(option_name, None) if attrtype: if attrtype == bool: def attrtype(input_text: str): @@ -1245,7 +1253,7 @@ class ServerCommandProcessor(CommonCommandProcessor): self.output(f"Set option {option_name} to {getattr(self.ctx, option_name)}") return True else: - known = (f"{option}:{otype}" for option, otype in self.simple_options.items()) + known = (f"{option}:{otype}" for option, otype in self.ctx.simple_options.items()) self.output(f"Unrecognized Option {option_name}, known: " f"{', '.join(known)}") return False diff --git a/Mystery.py b/Mystery.py index 2857521a1e..d74c9973aa 100644 --- a/Mystery.py +++ b/Mystery.py @@ -238,6 +238,8 @@ def convert_to_on_off(value): def get_choice(option, root, value=None) -> typing.Any: if option not in root: return value + if type(root[option]) is list: + return interpret_on_off(random.choices(root[option])[0]) if type(root[option]) is not dict: return interpret_on_off(root[option]) if not root[option]: @@ -488,6 +490,17 @@ def roll_settings(weights): ret.local_items = ",".join(ret.local_items) + ret.non_local_items = set() + for item_name in weights.get('non_local_items', []): + items = item_name_groups.get(item_name, {item_name}) + for item in items: + if item in item_table: + ret.non_local_items.add(item) + else: + raise Exception(f"Could not force item {item} to be world-non-local, as it was not recognized.") + + ret.non_local_items = ",".join(ret.non_local_items) + if 'rom' in weights: romweights = weights['rom'] diff --git a/Rom.py b/Rom.py index 37d8471344..d2d74e6e03 100644 --- a/Rom.py +++ b/Rom.py @@ -1,7 +1,7 @@ from __future__ import annotations JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'e3714804e3fae1c6ac6100b94d1aee62' +RANDOMIZERBASEHASH = '5a607e36a82bbd14180536c8ec3ae49b' import io import json @@ -697,12 +697,12 @@ def patch_rom(world, rom, player, team, enemized): # Thanks to Zarby89 for originally finding these values # todo fix screen scrolling - if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \ - exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', + if world.shuffle[player] not in {'insanity', 'insanity_legacy', 'madness_legacy'} and \ + exit.name in {'Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit', 'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)', - 'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']: + 'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)'}: # For exits that connot be reached from another, no need to apply offset fixes. rom.write_int16(0x15DB5 + 2 * offset, link_y) # same as final else elif room_id == 0x0059 and world.fix_skullwoods_exit[player]: @@ -1407,20 +1407,19 @@ def patch_rom(world, rom, player, team, enemized): rom.write_bytes(0x180185, [0, 0, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0, 0, 0]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0, 0, 0]) # Mantle respawn refills (magic, bombs, arrows) - if world.mode[player] == 'standard': - if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']: + if world.mode[player] == 'standard' and uncle_location.item and uncle_location.item.player == player: + if uncle_location.item.name in {'Bow', 'Progressive Bow'}: rom.write_byte(0x18004E, 1) # Escape Fill (arrows) rom.write_int16(0x180183, 300) # Escape fill rupee bow rom.write_bytes(0x180185, [0, 0, 70]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0, 0, 10]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0, 0, 10]) # Mantle respawn refills (magic, bombs, arrows) - elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']: + elif uncle_location.item.name in {'Bombs (10)'}: rom.write_byte(0x18004E, 2) # Escape Fill (bombs) rom.write_bytes(0x180185, [0, 50, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0, 3, 0]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0, 3, 0]) # Mantle respawn refills (magic, bombs, arrows) - elif uncle_location.item is not None and uncle_location.item.name in ['Cane of Somaria', 'Cane of Byrna', - 'Fire Rod']: + elif uncle_location.item.name in {'Cane of Somaria', 'Cane of Byrna', 'Fire Rod'}: rom.write_byte(0x18004E, 4) # Escape Fill (magic) rom.write_bytes(0x180185, [0x80, 0, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0x20, 0, 0]) # Zelda respawn refills (magic, bombs, arrows) @@ -1629,7 +1628,7 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr hud_palettes = palettes_options['hud'] sword_palettes = palettes_options['sword'] shield_palettes = palettes_options['shield'] - link_palettes = palettes_options['link'] + # link_palettes = palettes_options['link'] buildAndRandomize("randomize_dungeon", uw_palettes) buildAndRandomize("randomize_overworld", ow_palettes) buildAndRandomize("randomize_hud", hud_palettes) @@ -2062,9 +2061,10 @@ def write_strings(rom, world, player, team): greenpendant = world.find_items('Green Pendant', player)[0] tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant.hint_text - tt['sign_ganons_tower'] = ('You need %d crystal to enter.' if world.crystals_needed_for_gt[ - player] == 1 else 'You need %d crystals to enter.') % \ - world.crystals_needed_for_gt[player] + if world.crystals_needed_for_gt[player] == 1: + tt['sign_ganons_tower'] = 'You need a crystal to enter.' + else: + tt['sign_ganons_tower'] = f'You need {world.crystals_needed_for_gt[player]} crystals to enter.' if world.goal[player] == 'dungeons': tt['sign_ganon'] = 'You need to complete all the dungeons.' diff --git a/Rules.py b/Rules.py index b86060bcc7..04889a0f0d 100644 --- a/Rules.py +++ b/Rules.py @@ -104,7 +104,7 @@ def mirrorless_path_to_castle_courtyard(world, player): else: queue.append((entrance.connected_region, new_path)) - raise Exception(f"Could not find mirrorless path to castle courtyard for Player {player}") + raise Exception(f"Could not find mirrorless path to castle courtyard for Player {player} ({world.get_player_names(player)})") def set_rule(spot, rule): spot.access_rule = rule @@ -179,6 +179,10 @@ def locality_rules(world, player): for location in world.get_locations(): if location.player != player: forbid_items_for_player(location, world.local_items[player], player) + if world.non_local_items[player]: + for location in world.get_locations(): + if location.player == player: + forbid_items_for_player(location, world.non_local_items[player], player) non_crossover_items = (item_name_groups["Small Keys"] | item_name_groups["Big Keys"] | progression_items) - { diff --git a/Text.py b/Text.py index ba66506528..1c97abe116 100644 --- a/Text.py +++ b/Text.py @@ -267,7 +267,7 @@ junk_texts = [ "{C:GREEN}\n>Secret power\nis said to be\nin the arrow.", "{C:GREEN}\nAim at the\neyes of Gohma.\n >", "{C:GREEN}\nGrumble,\ngrumble…\n >", - "{C:GREEN}\n10th enemy\nhas the bomb.\n >", + # "{C:GREEN}\n10th enemy\nhas the bomb.\n >", removed as people may assume it applies to this game "{C:GREEN}\nGo to the\nnext room.\n >", "{C:GREEN}\n>Thanks, @\nYou’re the\nhero of Hyrule", "{C:GREEN}\nThere’s always\nmoney in the\nBanana Stand>", diff --git a/Utils.py b/Utils.py index c2d893e77a..fe7d726d8f 100644 --- a/Utils.py +++ b/Utils.py @@ -6,7 +6,7 @@ def tuplize_version(version: str) -> typing.Tuple[int, ...]: return tuple(int(piece, 10) for piece in version.split(".")) -__version__ = "3.3.0" +__version__ = "3.4.1" _version_tuple = tuplize_version(__version__) import os @@ -165,6 +165,90 @@ def get_public_ipv6() -> str: pass # we could be offline, in a local game, or ipv6 may not be available return ip + +def get_default_options() -> dict: + if not hasattr(get_default_options, "options"): + options = dict() + + # Refer to host.yaml for comments as to what all these options mean. + generaloptions = dict() + generaloptions["rom_file"] = "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc" + generaloptions["qusb2snes"] = "QUsb2Snes\\QUsb2Snes.exe" + generaloptions["rom_start"] = True + generaloptions["output_path"] = "output" + options["general_options"] = generaloptions + + serveroptions = dict() + serveroptions["host"] = None + serveroptions["port"] = 38281 + serveroptions["password"] = None + serveroptions["multidata"] = None + serveroptions["savefile"] = None + serveroptions["disable_save"] = False + serveroptions["loglevel"] = "info" + serveroptions["server_password"] = None + serveroptions["disable_item_cheat"] = False + serveroptions["location_check_points"] = 1 + serveroptions["hint_cost"] = 1000 + serveroptions["forfeit_mode"] = "goal" + serveroptions["remaining_mode"] = "goal" + serveroptions["auto_shutdown"] = 0 + serveroptions["compatibility"] = 2 + options["server_options"] = serveroptions + + multimysteryoptions = dict() + multimysteryoptions["teams"] = 1 + multimysteryoptions["enemizer_path"] = "EnemizerCLI/EnemizerCLI.Core.exe" + multimysteryoptions["player_files_path"] = "Players" + multimysteryoptions["players"] = 0 + multimysteryoptions["weights_file_path"] = "weights.yaml" + multimysteryoptions["meta_file_path"] = "meta.yaml" + multimysteryoptions["player_name"] = "" + multimysteryoptions["create_spoiler"] = 1 + multimysteryoptions["zip_roms"] = 0 + multimysteryoptions["zip_diffs"] = 2 + multimysteryoptions["zip_spoiler"] = 0 + multimysteryoptions["zip_multidata"] = 1 + multimysteryoptions["zip_format"] = 1 + multimysteryoptions["race"] = 0 + multimysteryoptions["cpu_threads"] = 0 + multimysteryoptions["max_attempts"] = 0 + multimysteryoptions["take_first_working"] = False + multimysteryoptions["keep_all_seeds"] = False + multimysteryoptions["log_output_path"] = "Output Logs" + multimysteryoptions["log_level"] = None + options["multi_mystery_options"] = multimysteryoptions + get_default_options.options = options + return get_default_options.options + + +blacklisted_options = {"multi_mystery_options.cpu_threads", + "multi_mystery_options.max_attempts", + "multi_mystery_options.take_first_working", + "multi_mystery_options.keep_all_seeds", + "multi_mystery_options.log_output_path", + "multi_mystery_options.log_level"} + + +def update_options(src: dict, dest: dict, filename: str, keys: list) -> dict: + import logging + for key, value in src.items(): + new_keys = keys.copy() + new_keys.append(key) + option_name = '.'.join(new_keys) + if key not in dest: + dest[key] = value + if filename.endswith("options.yaml") and option_name not in blacklisted_options: + logging.info(f"Warning: {filename} is missing {option_name}") + elif isinstance(value, dict): + if not isinstance(dest.get(key, None), dict): + if filename.endswith("options.yaml") and option_name not in blacklisted_options: + logging.info(f"Warning: {filename} has {option_name}, but it is not a dictionary. overwriting.") + dest[key] = value + else: + dest[key] = update_options(value, dest[key], filename, new_keys) + return dest + def get_options() -> dict: if not hasattr(get_options, "options"): locations = ("options.yaml", "host.yaml", @@ -173,7 +257,9 @@ def get_options() -> dict: for location in locations: if os.path.exists(location): with open(location) as f: - get_options.options = parse_yaml(f.read()) + options = parse_yaml(f.read()) + + get_options.options = update_options(get_default_options(), options, location, list()) break else: raise FileNotFoundError(f"Could not find {locations[1]} to load options.") @@ -222,28 +308,32 @@ def get_adjuster_settings(romfile: str) -> typing.Tuple[str, bool]: if hasattr(get_adjuster_settings, "adjuster_settings"): adjuster_settings = getattr(get_adjuster_settings, "adjuster_settings") else: - adjuster_settings = persistent_load().get("adjuster", {}).get("last_settings", {}) + adjuster_settings = persistent_load().get("adjuster", {}).get("last_settings_3", {}) + if adjuster_settings: import pprint import Patch adjuster_settings.rom = romfile adjuster_settings.baserom = Patch.get_base_rom_path() whitelist = {"disablemusic", "fastmenu", "heartbeep", "heartcolor", "ow_palettes", "quickswap", - "uw_palettes"} + "uw_palettes", "sprite"} printed_options = {name: value for name, value in vars(adjuster_settings).items() if name in whitelist} - sprite = getattr(adjuster_settings, "sprite", None) - if sprite: - printed_options["sprite"] = adjuster_settings.sprite.name + if hasattr(get_adjuster_settings, "adjust_wanted"): adjust_wanted = getattr(get_adjuster_settings, "adjust_wanted") + elif persistent_load().get("adjuster", {}).get("never_adjust", False): # never adjust, per user request + return romfile, False else: adjust_wanted = input(f"Last used adjuster settings were found. Would you like to apply these? \n" f"{pprint.pformat(printed_options)}\n" - f"Enter yes or no: ") + f"Enter yes, no or never: ") if adjust_wanted and adjust_wanted.startswith("y"): adjusted = True import AdjusterMain _, romfile = AdjusterMain.adjust(adjuster_settings) + elif adjust_wanted and "never" in adjust_wanted: + persistent_store("adjuster", "never_adjust", True) + return romfile, False else: adjusted = False import logging diff --git a/WebHostLib/__init__.py b/WebHostLib/__init__.py index 8b6f10dded..4942dfef99 100644 --- a/WebHostLib/__init__.py +++ b/WebHostLib/__init__.py @@ -47,6 +47,8 @@ app.config["PONY"] = { } app.config["MAX_ROLL"] = 20 app.config["CACHE_TYPE"] = "simple" +app.config["JSON_AS_ASCII"] = False + app.autoversion = True av = Autoversion(app) cache = Cache(app) @@ -145,4 +147,5 @@ def favicon(): from WebHostLib.customserver import run_server_process -from . import tracker, upload, landing, check, generate, downloads # to trigger app routing picking up on it +from . import tracker, upload, landing, check, generate, downloads, api # to trigger app routing picking up on it +app.register_blueprint(api.api_endpoints) \ No newline at end of file diff --git a/WebHostLib/api/__init__.py b/WebHostLib/api/__init__.py new file mode 100644 index 0000000000..abe4aeb2f4 --- /dev/null +++ b/WebHostLib/api/__init__.py @@ -0,0 +1,23 @@ +"""API endpoints package.""" +from uuid import UUID + +from flask import Blueprint, abort + +from ..models import Room + +api_endpoints = Blueprint('api', __name__, url_prefix="/api") + +from . import generate + +# unsorted/misc endpoints + +@api_endpoints.route('/room_status/') +def room_info(room: UUID): + room = Room.get(id=room) + if room is None: + return abort(404) + return {"tracker": room.tracker, + "players": room.seed.multidata["names"], + "last_port": room.last_port, + "last_activity": room.last_activity, + "timeout": room.timeout} \ No newline at end of file diff --git a/WebHostLib/api/generate.py b/WebHostLib/api/generate.py new file mode 100644 index 0000000000..4b5ea7107e --- /dev/null +++ b/WebHostLib/api/generate.py @@ -0,0 +1,73 @@ +import pickle +from uuid import UUID + +from . import api_endpoints +from flask import request, session, url_for +from pony.orm import commit + +from WebHostLib import app, Generation, STATE_QUEUED, Seed, STATE_ERROR +from WebHostLib.check import get_yaml_data, roll_options + + +@api_endpoints.route('/generate', methods=['POST']) +def generate_api(): + try: + options = {} + race = False + + if 'file' in request.files: + file = request.files['file'] + options = get_yaml_data(file) + if type(options) == str: + return {"text": options}, 400 + if "race" in request.form: + race = bool(0 if request.form["race"] in {"false"} else int(request.form["race"])) + + json_data = request.get_json() + if json_data: + if 'weights' in json_data: + # example: options = {"player1weights" : {}} + options = json_data["weights"] + if "race" in json_data: + race = bool(0 if json_data["race"] in {"false"} else int(json_data["race"])) + if not options: + return {"text": "No options found. Expected file attachment or json weights." + }, 400 + + if len(options) > app.config["MAX_ROLL"]: + return {"text": "Max size of multiworld exceeded", + "detail": app.config["MAX_ROLL"]}, 409 + + results, gen_options = roll_options(options) + if any(type(result) == str for result in results.values()): + return {"text": str(results), + "detail": results}, 400 + else: + gen = Generation( + options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}), + # convert to json compatible + meta=pickle.dumps({"race": race}), state=STATE_QUEUED, + owner=session["_id"]) + commit() + return {"text": f"Generation of seed {gen.id} started successfully.", + "detail": gen.id, + "encoded": app.url_map.converters["suuid"].to_url(None, gen.id), + "wait_api_url": url_for("wait_seed_api", seed=gen.id, _external=True), + "url": url_for("wait_seed", seed=gen.id, _external=True)}, 201 + except Exception as e: + return {"text": "Uncaught Exception:" + str(e)}, 500 + + +@api_endpoints.route('/status/') +def wait_seed_api(seed: UUID): + seed_id = seed + seed = Seed.get(id=seed_id) + if seed: + return {"text": "Generation done"}, 201 + generation = Generation.get(id=seed_id) + + if not generation: + return {"text": "Generation not found"}, 404 + elif generation.state == STATE_ERROR: + return {"text": "Generation failed"}, 500 + return {"text": "Generation running"}, 202 diff --git a/WebHostLib/customserver.py b/WebHostLib/customserver.py index 4a6ffc3654..4831cd79ef 100644 --- a/WebHostLib/customserver.py +++ b/WebHostLib/customserver.py @@ -47,7 +47,7 @@ class DBCommandProcessor(ServerCommandProcessor): class WebHostContext(Context): def __init__(self): - super(WebHostContext, self).__init__("", 0, "", 1, 40, True, "enabled", "enabled", 0, 2) + super(WebHostContext, self).__init__("", 0, "", "", 1, 40, True, "enabled", "enabled", 0, 2) self.main_loop = asyncio.get_running_loop() self.video = {} self.tags = ["Berserker", "WebHost"] diff --git a/WebHostLib/generate.py b/WebHostLib/generate.py index b26e2c7be5..d8c78ee02e 100644 --- a/WebHostLib/generate.py +++ b/WebHostLib/generate.py @@ -52,55 +52,6 @@ def generate(race=False): return render_template("generate.html", race=race) -@app.route('/api/generate', methods=['POST']) -def generate_api(): - try: - options = {} - race = False - - if 'file' in request.files: - file = request.files['file'] - options = get_yaml_data(file) - if type(options) == str: - return {"text": options}, 400 - if "race" in request.form: - race = bool(0 if request.form["race"] in {"false"} else int(request.form["race"])) - - json_data = request.get_json() - if json_data: - if 'weights' in json_data: - # example: options = {"player1weights" : {}} - options = json_data["weights"] - if "race" in json_data: - race = bool(0 if json_data["race"] in {"false"} else int(json_data["race"])) - if not options: - return {"text": "No options found. Expected file attachment or json weights." - }, 400 - - if len(options) > app.config["MAX_ROLL"]: - return {"text": "Max size of multiworld exceeded", - "detail": app.config["MAX_ROLL"]}, 409 - - results, gen_options = roll_options(options) - if any(type(result) == str for result in results.values()): - return {"text": str(results), - "detail": results}, 400 - else: - gen = Generation( - options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}), - # convert to json compatible - meta=pickle.dumps({"race": race}), state=STATE_QUEUED, - owner=session["_id"]) - commit() - return {"text": f"Generation of seed {gen.id} started successfully.", - "detail": gen.id, - "encoded": app.url_map.converters["suuid"].to_url(None, gen.id), - "wait_api_url": url_for("wait_seed_api", seed=gen.id), - "url": url_for("wait_seed", seed=gen.id)}, 201 - except Exception as e: - return {"text": "Uncaught Exception:" + str(e)}, 500 - - def gen_game(gen_options, race=False, owner=None, sid=None): try: target = tempfile.TemporaryDirectory() @@ -142,12 +93,13 @@ def gen_game(gen_options, race=False, owner=None, sid=None): ERmain(erargs, seed) return upload_to_db(target.name, owner, sid, race) - except BaseException: + except BaseException as e: if sid: with db_session: gen = Generation.get(id=sid) if gen is not None: gen.state = STATE_ERROR + gen.meta = (e.__class__.__name__ + ": "+ str(e)).encode() raise @@ -162,25 +114,11 @@ def wait_seed(seed: UUID): if not generation: return "Generation not found." elif generation.state == STATE_ERROR: - return "Generation failed, please retry." + import html + return f"Generation failed, please retry.
{html.escape(generation.meta.decode())}" return render_template("waitSeed.html", seed_id=seed_id) -@app.route('/api/status/') -def wait_seed_api(seed: UUID): - seed_id = seed - seed = Seed.get(id=seed_id) - if seed: - return {"text": "Generation done"}, 201 - generation = Generation.get(id=seed_id) - - if not generation: - return {"text": "Generation not found"}, 404 - elif generation.state == STATE_ERROR: - return {"text": "Generation failed"}, 500 - return {"text": "Generation running"}, 202 - - def upload_to_db(folder, owner, sid, race:bool): patches = set() spoiler = "" diff --git a/WebHostLib/models.py b/WebHostLib/models.py index d5e0f2b807..77bd6f2fed 100644 --- a/WebHostLib/models.py +++ b/WebHostLib/models.py @@ -50,5 +50,5 @@ class Generation(db.Entity): id = PrimaryKey(UUID, default=uuid4) owner = Required(UUID) options = Required(bytes, lazy=True) # these didn't work as JSON on mariaDB, so they're getting pickled now - meta = Required(bytes, lazy=True) + meta = Required(bytes, lazy=True) # if state is -1 (error) this will contain an utf-8 encoded error message state = Required(int, default=0, index=True) diff --git a/WebHostLib/requirements.txt b/WebHostLib/requirements.txt index 52aa607d76..f7a97f6567 100644 --- a/WebHostLib/requirements.txt +++ b/WebHostLib/requirements.txt @@ -1,7 +1,7 @@ flask>=1.1.2 -pony>=0.7.13 +pony>=0.7.14 waitress>=1.4.4 flask-caching>=1.9.0 Flask-Autoversion>=0.2.0 -Flask-Compress>=1.7.0 +Flask-Compress>=1.8.0 Flask-Limiter>=1.4 diff --git a/WebHostLib/static/static/playerSettings.json b/WebHostLib/static/static/playerSettings.json index dbbbbc7573..e6ee539f48 100644 --- a/WebHostLib/static/static/playerSettings.json +++ b/WebHostLib/static/static/playerSettings.json @@ -791,12 +791,6 @@ "friendlyName": "Expert", "description": "Minimum upgrade availability (max: 8 hearts, green mail, master sword, fighter shield, no silvers unless swordless).", "defaultValue": 0 - }, - "crowd_control": { - "keyString": "item_pool.crowd_control", - "friendlyName": "Crowd Control", - "description": "Configures the item pool for the crowd control extension. Do not use this unless you are using crowd control.", - "defaultValue": 0 } } }, @@ -1387,6 +1381,26 @@ "defaultValue": 0 } } + }, + "key_drop_shuffle": { + "keyString": "key_drop_shuffle", + "friendlyName": "Key Drop Shuffle", + "description": "Allows the small/big keys dropped by enemies/pots to be shuffled into the item pool. This extends the number of checks from 216 to 249", + "inputType": "range", + "subOptions": { + "on": { + "keyString": "key_drop_shuffle.on", + "friendlyName": "Enabled", + "description": "Enables key drop shuffle", + "defaultValue": 0 + }, + "off": { + "keyString": "key_drop_shuffle.off", + "friendlyName": "Disabled", + "description": "Disables key drop shuffle", + "defaultValue": 50 + } + } } }, "romOptions": { diff --git a/WebHostLib/static/static/playerSettings.yaml b/WebHostLib/static/static/playerSettings.yaml index 379e18a475..b6e7747fc6 100644 --- a/WebHostLib/static/static/playerSettings.yaml +++ b/WebHostLib/static/static/playerSettings.yaml @@ -165,7 +165,6 @@ item_pool: normal: 50 # Item availability remains unchanged from vanilla game hard: 0 # Reduced upgrade availability (max: 14 hearts, blue mail, tempered sword, fire shield, no silvers unless swordless) expert: 0 # Minimum upgrade availability (max: 8 hearts, green mail, master sword, fighter shield, no silvers unless swordless) - crowd_control: 0 # Sets up the item pool for the crowd control extension. Do not use it without crowd control item_functionality: easy: 0 # Allow Hammer to damage ganon, Allow Hammer tablet collection, Allow swordless medallion use everywhere. normal: 50 # Vanilla item functionality @@ -305,6 +304,9 @@ intensity: # Only available if the host uses the doors branch, it is ignored oth 2: 0 # And shuffles open edges and straight staircases 3: 0 # And shuffles dungeon lobbies random: 0 # Picks one of those at random +key_drop_shuffle: # Only available if the host uses the doors branch, it is ignored otherwise + on: 0 # Enables the small keys dropped by enemies or under pots, and the big key dropped by the Ball & Chain guard to be shuffled into the pool. This extends the number of checks to 249. + off: 50 experimental: # Only available if the host uses the doors branch, it is ignored otherwise on: 0 # Enables experimental features. Currently, this is just the dungeon keys in chest counter. off: 50 diff --git a/WebHostLib/static/styles/player-settings.css b/WebHostLib/static/styles/player-settings.css index edcec21482..d4ce6a6032 100644 --- a/WebHostLib/static/styles/player-settings.css +++ b/WebHostLib/static/styles/player-settings.css @@ -55,6 +55,7 @@ html{ #player-settings #settings-wrapper #sprite-picker .sprite-img-wrapper{ cursor: pointer; margin: 10px; + image-rendering: pixelated; } /* Center tooltip text for sprite images */ diff --git a/data/basepatch.bmbp b/data/basepatch.bmbp index 8ed7084b6a..564edb17d8 100644 Binary files a/data/basepatch.bmbp and b/data/basepatch.bmbp differ diff --git a/data/sprites/alttpr/.gitignore b/data/sprites/alttpr/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/data/sprites/alttpr/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/data/sprites/alttpr/001.link.1.zspr b/data/sprites/alttpr/001.link.1.zspr deleted file mode 100644 index 4537afa84b..0000000000 Binary files a/data/sprites/alttpr/001.link.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/4slink-armors.1.zspr b/data/sprites/alttpr/4slink-armors.1.zspr deleted file mode 100644 index 7a94411333..0000000000 Binary files a/data/sprites/alttpr/4slink-armors.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/abigail.1.zspr b/data/sprites/alttpr/abigail.1.zspr deleted file mode 100644 index 526990c5ef..0000000000 Binary files a/data/sprites/alttpr/abigail.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/adol.1.zspr b/data/sprites/alttpr/adol.1.zspr deleted file mode 100644 index da8210a956..0000000000 Binary files a/data/sprites/alttpr/adol.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/aggretsuko.1.zspr b/data/sprites/alttpr/aggretsuko.1.zspr deleted file mode 100644 index c23d9d8316..0000000000 Binary files a/data/sprites/alttpr/aggretsuko.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/alice.1.zspr b/data/sprites/alttpr/alice.1.zspr deleted file mode 100644 index 4c673acd71..0000000000 Binary files a/data/sprites/alttpr/alice.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/angry-video-game-nerd.1.zspr b/data/sprites/alttpr/angry-video-game-nerd.1.zspr deleted file mode 100644 index 79aee561cf..0000000000 Binary files a/data/sprites/alttpr/angry-video-game-nerd.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/arcane.1.zspr b/data/sprites/alttpr/arcane.1.zspr deleted file mode 100644 index b0fd476050..0000000000 Binary files a/data/sprites/alttpr/arcane.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ark.2.zspr b/data/sprites/alttpr/ark.2.zspr deleted file mode 100644 index 916b036aa3..0000000000 Binary files a/data/sprites/alttpr/ark.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/arrghus.2.zspr b/data/sprites/alttpr/arrghus.2.zspr deleted file mode 100644 index 2064009d3c..0000000000 Binary files a/data/sprites/alttpr/arrghus.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/astronaut.1.zspr b/data/sprites/alttpr/astronaut.1.zspr deleted file mode 100644 index a4db3020a3..0000000000 Binary files a/data/sprites/alttpr/astronaut.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/badeline.1.zspr b/data/sprites/alttpr/badeline.1.zspr deleted file mode 100644 index b9fb134606..0000000000 Binary files a/data/sprites/alttpr/badeline.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bananas-in-pyjamas.1.zspr b/data/sprites/alttpr/bananas-in-pyjamas.1.zspr deleted file mode 100644 index f75af2b219..0000000000 Binary files a/data/sprites/alttpr/bananas-in-pyjamas.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bandit.1.zspr b/data/sprites/alttpr/bandit.1.zspr deleted file mode 100644 index 5b3288f80d..0000000000 Binary files a/data/sprites/alttpr/bandit.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/batman.1.zspr b/data/sprites/alttpr/batman.1.zspr deleted file mode 100644 index a4a1e9c0ef..0000000000 Binary files a/data/sprites/alttpr/batman.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/beau.1.zspr b/data/sprites/alttpr/beau.1.zspr deleted file mode 100644 index 8d8d2079bf..0000000000 Binary files a/data/sprites/alttpr/beau.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bewp.1.zspr b/data/sprites/alttpr/bewp.1.zspr deleted file mode 100644 index 265d2e1a61..0000000000 Binary files a/data/sprites/alttpr/bewp.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bigkey.1.zspr b/data/sprites/alttpr/bigkey.1.zspr deleted file mode 100644 index eab4854e38..0000000000 Binary files a/data/sprites/alttpr/bigkey.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/birb.1.zspr b/data/sprites/alttpr/birb.1.zspr deleted file mode 100644 index d6d86bb688..0000000000 Binary files a/data/sprites/alttpr/birb.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/birdo.1.zspr b/data/sprites/alttpr/birdo.1.zspr deleted file mode 100644 index 54c49747ca..0000000000 Binary files a/data/sprites/alttpr/birdo.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/blackmage.1.zspr b/data/sprites/alttpr/blackmage.1.zspr deleted file mode 100644 index d9b5628852..0000000000 Binary files a/data/sprites/alttpr/blackmage.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/blacksmithlink.1.zspr b/data/sprites/alttpr/blacksmithlink.1.zspr deleted file mode 100644 index e9aeb31aa3..0000000000 Binary files a/data/sprites/alttpr/blacksmithlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/blossom.1.zspr b/data/sprites/alttpr/blossom.1.zspr deleted file mode 100644 index 57f4918c55..0000000000 Binary files a/data/sprites/alttpr/blossom.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bob.1.zspr b/data/sprites/alttpr/bob.1.zspr deleted file mode 100644 index 25fc041084..0000000000 Binary files a/data/sprites/alttpr/bob.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/boo-two.1.zspr b/data/sprites/alttpr/boo-two.1.zspr deleted file mode 100644 index a5c5463c23..0000000000 Binary files a/data/sprites/alttpr/boo-two.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/boo.2.zspr b/data/sprites/alttpr/boo.2.zspr deleted file mode 100644 index 24c74bde23..0000000000 Binary files a/data/sprites/alttpr/boo.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bottle_o_goo.1.zspr b/data/sprites/alttpr/bottle_o_goo.1.zspr deleted file mode 100644 index 28ca1f9b69..0000000000 Binary files a/data/sprites/alttpr/bottle_o_goo.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/botw-zelda.1.zspr b/data/sprites/alttpr/botw-zelda.1.zspr deleted file mode 100644 index 630adfa622..0000000000 Binary files a/data/sprites/alttpr/botw-zelda.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bowser.1.zspr b/data/sprites/alttpr/bowser.1.zspr deleted file mode 100644 index 1cc256d8c3..0000000000 Binary files a/data/sprites/alttpr/bowser.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/branch.1.zspr b/data/sprites/alttpr/branch.1.zspr deleted file mode 100644 index b79264183b..0000000000 Binary files a/data/sprites/alttpr/branch.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/brian.1.zspr b/data/sprites/alttpr/brian.1.zspr deleted file mode 100644 index 013a220794..0000000000 Binary files a/data/sprites/alttpr/brian.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/broccoli.1.zspr b/data/sprites/alttpr/broccoli.1.zspr deleted file mode 100644 index e335df01e4..0000000000 Binary files a/data/sprites/alttpr/broccoli.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bronzor.1.zspr b/data/sprites/alttpr/bronzor.1.zspr deleted file mode 100644 index d1afd11701..0000000000 Binary files a/data/sprites/alttpr/bronzor.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bsboy.1.zspr b/data/sprites/alttpr/bsboy.1.zspr deleted file mode 100644 index 7d00be7451..0000000000 Binary files a/data/sprites/alttpr/bsboy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bsgirl.1.zspr b/data/sprites/alttpr/bsgirl.1.zspr deleted file mode 100644 index 829237518c..0000000000 Binary files a/data/sprites/alttpr/bsgirl.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bubbles.1.zspr b/data/sprites/alttpr/bubbles.1.zspr deleted file mode 100644 index bbba3b7546..0000000000 Binary files a/data/sprites/alttpr/bubbles.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/bullet_bill.1.zspr b/data/sprites/alttpr/bullet_bill.1.zspr deleted file mode 100644 index 5b561b9eee..0000000000 Binary files a/data/sprites/alttpr/bullet_bill.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/buttercup.1.zspr b/data/sprites/alttpr/buttercup.1.zspr deleted file mode 100644 index bd066c2743..0000000000 Binary files a/data/sprites/alttpr/buttercup.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cactuar.1.zspr b/data/sprites/alttpr/cactuar.1.zspr deleted file mode 100644 index 51c3289362..0000000000 Binary files a/data/sprites/alttpr/cactuar.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cadence.1.zspr b/data/sprites/alttpr/cadence.1.zspr deleted file mode 100644 index 05f174f7cf..0000000000 Binary files a/data/sprites/alttpr/cadence.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/carlsagan42.1.zspr b/data/sprites/alttpr/carlsagan42.1.zspr deleted file mode 100644 index 2632cb6f1b..0000000000 Binary files a/data/sprites/alttpr/carlsagan42.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/casual-zelda.1.zspr b/data/sprites/alttpr/casual-zelda.1.zspr deleted file mode 100644 index 80257f11a3..0000000000 Binary files a/data/sprites/alttpr/casual-zelda.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cat.3.zspr b/data/sprites/alttpr/cat.3.zspr deleted file mode 100644 index 69946d73f8..0000000000 Binary files a/data/sprites/alttpr/cat.3.zspr and /dev/null differ diff --git a/data/sprites/alttpr/catboo.1.zspr b/data/sprites/alttpr/catboo.1.zspr deleted file mode 100644 index 45a4fa8103..0000000000 Binary files a/data/sprites/alttpr/catboo.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cdilink.1.zspr b/data/sprites/alttpr/cdilink.1.zspr deleted file mode 100644 index 3236f7999b..0000000000 Binary files a/data/sprites/alttpr/cdilink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/celes.1.zspr b/data/sprites/alttpr/celes.1.zspr deleted file mode 100644 index ac0c122695..0000000000 Binary files a/data/sprites/alttpr/celes.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/charizard.1.zspr b/data/sprites/alttpr/charizard.1.zspr deleted file mode 100644 index babed51157..0000000000 Binary files a/data/sprites/alttpr/charizard.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cheepcheep.1.zspr b/data/sprites/alttpr/cheepcheep.1.zspr deleted file mode 100644 index a49545f208..0000000000 Binary files a/data/sprites/alttpr/cheepcheep.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/chibity.1.zspr b/data/sprites/alttpr/chibity.1.zspr deleted file mode 100644 index 949dbe2eaf..0000000000 Binary files a/data/sprites/alttpr/chibity.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cirno.1.zspr b/data/sprites/alttpr/cirno.1.zspr deleted file mode 100644 index 75de8ab69e..0000000000 Binary files a/data/sprites/alttpr/cirno.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/clifford.1.zspr b/data/sprites/alttpr/clifford.1.zspr deleted file mode 100644 index 73f848c16e..0000000000 Binary files a/data/sprites/alttpr/clifford.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/clyde.1.zspr b/data/sprites/alttpr/clyde.1.zspr deleted file mode 100644 index b590a2ef91..0000000000 Binary files a/data/sprites/alttpr/clyde.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/conker.1.zspr b/data/sprites/alttpr/conker.1.zspr deleted file mode 100644 index 121d523330..0000000000 Binary files a/data/sprites/alttpr/conker.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cornelius.1.zspr b/data/sprites/alttpr/cornelius.1.zspr deleted file mode 100644 index 4c58f35610..0000000000 Binary files a/data/sprites/alttpr/cornelius.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/corona.1.zspr b/data/sprites/alttpr/corona.1.zspr deleted file mode 100644 index 2ed39a78eb..0000000000 Binary files a/data/sprites/alttpr/corona.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cucco.1.zspr b/data/sprites/alttpr/cucco.1.zspr deleted file mode 100644 index f237de4ab0..0000000000 Binary files a/data/sprites/alttpr/cucco.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/cursor.1.zspr b/data/sprites/alttpr/cursor.1.zspr deleted file mode 100644 index 45bc973919..0000000000 Binary files a/data/sprites/alttpr/cursor.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/d_owls.1.zspr b/data/sprites/alttpr/d_owls.1.zspr deleted file mode 100644 index 147283ea84..0000000000 Binary files a/data/sprites/alttpr/d_owls.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/dark-panda.1.zspr b/data/sprites/alttpr/dark-panda.1.zspr deleted file mode 100644 index 1b39b74712..0000000000 Binary files a/data/sprites/alttpr/dark-panda.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darkboy.1.zspr b/data/sprites/alttpr/darkboy.1.zspr deleted file mode 100644 index de55ebbe36..0000000000 Binary files a/data/sprites/alttpr/darkboy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darkgirl.1.zspr b/data/sprites/alttpr/darkgirl.1.zspr deleted file mode 100644 index 8fd848fd9f..0000000000 Binary files a/data/sprites/alttpr/darkgirl.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darklink-tunic.1.zspr b/data/sprites/alttpr/darklink-tunic.1.zspr deleted file mode 100644 index fe41730884..0000000000 Binary files a/data/sprites/alttpr/darklink-tunic.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darklink.1.zspr b/data/sprites/alttpr/darklink.1.zspr deleted file mode 100644 index b0d9a95f47..0000000000 Binary files a/data/sprites/alttpr/darklink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darkswatchy.1.zspr b/data/sprites/alttpr/darkswatchy.1.zspr deleted file mode 100644 index 88677425b6..0000000000 Binary files a/data/sprites/alttpr/darkswatchy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darkzelda.1.zspr b/data/sprites/alttpr/darkzelda.1.zspr deleted file mode 100644 index 519c278a1a..0000000000 Binary files a/data/sprites/alttpr/darkzelda.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/darkzora.2.zspr b/data/sprites/alttpr/darkzora.2.zspr deleted file mode 100644 index fbb15c69f9..0000000000 Binary files a/data/sprites/alttpr/darkzora.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/deadpool-mythic.1.zspr b/data/sprites/alttpr/deadpool-mythic.1.zspr deleted file mode 100644 index abcda92659..0000000000 Binary files a/data/sprites/alttpr/deadpool-mythic.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/deadpool.1.zspr b/data/sprites/alttpr/deadpool.1.zspr deleted file mode 100644 index 3d2e87f741..0000000000 Binary files a/data/sprites/alttpr/deadpool.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/deadrock.1.zspr b/data/sprites/alttpr/deadrock.1.zspr deleted file mode 100644 index cc28cd7902..0000000000 Binary files a/data/sprites/alttpr/deadrock.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/decidueye.1.zspr b/data/sprites/alttpr/decidueye.1.zspr deleted file mode 100644 index 1c769e6229..0000000000 Binary files a/data/sprites/alttpr/decidueye.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/demonlink.1.zspr b/data/sprites/alttpr/demonlink.1.zspr deleted file mode 100644 index 2daf73593d..0000000000 Binary files a/data/sprites/alttpr/demonlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/dragonite.2.zspr b/data/sprites/alttpr/dragonite.2.zspr deleted file mode 100644 index 37d95ad0a5..0000000000 Binary files a/data/sprites/alttpr/dragonite.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/drake.1.zspr b/data/sprites/alttpr/drake.1.zspr deleted file mode 100644 index 1be94a7567..0000000000 Binary files a/data/sprites/alttpr/drake.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/eggplant.1.zspr b/data/sprites/alttpr/eggplant.1.zspr deleted file mode 100644 index c33c200896..0000000000 Binary files a/data/sprites/alttpr/eggplant.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/emosaru.1.zspr b/data/sprites/alttpr/emosaru.1.zspr deleted file mode 100644 index a636dad950..0000000000 Binary files a/data/sprites/alttpr/emosaru.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ezlo.1.zspr b/data/sprites/alttpr/ezlo.1.zspr deleted file mode 100644 index 54596847db..0000000000 Binary files a/data/sprites/alttpr/ezlo.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/fierce-deity-link.1.zspr b/data/sprites/alttpr/fierce-deity-link.1.zspr deleted file mode 100644 index 770b89de7a..0000000000 Binary files a/data/sprites/alttpr/fierce-deity-link.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/finn.3.zspr b/data/sprites/alttpr/finn.3.zspr deleted file mode 100644 index 265b197cd6..0000000000 Binary files a/data/sprites/alttpr/finn.3.zspr and /dev/null differ diff --git a/data/sprites/alttpr/finny_bear.1.zspr b/data/sprites/alttpr/finny_bear.1.zspr deleted file mode 100644 index 9c3a530b10..0000000000 Binary files a/data/sprites/alttpr/finny_bear.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/fish_floodgate.1.zspr b/data/sprites/alttpr/fish_floodgate.1.zspr deleted file mode 100644 index 86684e7d8e..0000000000 Binary files a/data/sprites/alttpr/fish_floodgate.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/flavor_guy.1.zspr b/data/sprites/alttpr/flavor_guy.1.zspr deleted file mode 100644 index 5e1df365b3..0000000000 Binary files a/data/sprites/alttpr/flavor_guy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/foxlink.1.zspr b/data/sprites/alttpr/foxlink.1.zspr deleted file mode 100644 index d6eaf4337f..0000000000 Binary files a/data/sprites/alttpr/foxlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/freya.1.zspr b/data/sprites/alttpr/freya.1.zspr deleted file mode 100644 index b43338d577..0000000000 Binary files a/data/sprites/alttpr/freya.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/frisk.1.zspr b/data/sprites/alttpr/frisk.1.zspr deleted file mode 100644 index d521cae391..0000000000 Binary files a/data/sprites/alttpr/frisk.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/froglink.3.zspr b/data/sprites/alttpr/froglink.3.zspr deleted file mode 100644 index f5c46d8294..0000000000 Binary files a/data/sprites/alttpr/froglink.3.zspr and /dev/null differ diff --git a/data/sprites/alttpr/fujin.2.zspr b/data/sprites/alttpr/fujin.2.zspr deleted file mode 100644 index 9254ff7b1e..0000000000 Binary files a/data/sprites/alttpr/fujin.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/future_trunks.1.zspr b/data/sprites/alttpr/future_trunks.1.zspr deleted file mode 100644 index 456e64c786..0000000000 Binary files a/data/sprites/alttpr/future_trunks.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/gamer.1.zspr b/data/sprites/alttpr/gamer.1.zspr deleted file mode 100644 index 9f78d894f7..0000000000 Binary files a/data/sprites/alttpr/gamer.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ganon.1.zspr b/data/sprites/alttpr/ganon.1.zspr deleted file mode 100644 index a6adda4332..0000000000 Binary files a/data/sprites/alttpr/ganon.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ganondorf.1.zspr b/data/sprites/alttpr/ganondorf.1.zspr deleted file mode 100644 index 5bb6f54833..0000000000 Binary files a/data/sprites/alttpr/ganondorf.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/garfield.2.zspr b/data/sprites/alttpr/garfield.2.zspr deleted file mode 100644 index 6ca890e850..0000000000 Binary files a/data/sprites/alttpr/garfield.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/garnet.1.zspr b/data/sprites/alttpr/garnet.1.zspr deleted file mode 100644 index 858497c76f..0000000000 Binary files a/data/sprites/alttpr/garnet.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/garomaster.1.zspr b/data/sprites/alttpr/garomaster.1.zspr deleted file mode 100644 index 65b9959d47..0000000000 Binary files a/data/sprites/alttpr/garomaster.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/gbc-link.1.zspr b/data/sprites/alttpr/gbc-link.1.zspr deleted file mode 100644 index e98a6d08de..0000000000 Binary files a/data/sprites/alttpr/gbc-link.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/geno.1.zspr b/data/sprites/alttpr/geno.1.zspr deleted file mode 100644 index 3d747a2ae7..0000000000 Binary files a/data/sprites/alttpr/geno.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/gobli.1.zspr b/data/sprites/alttpr/gobli.1.zspr deleted file mode 100644 index 51dd119269..0000000000 Binary files a/data/sprites/alttpr/gobli.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/goomba.1.zspr b/data/sprites/alttpr/goomba.1.zspr deleted file mode 100644 index 0438682fe0..0000000000 Binary files a/data/sprites/alttpr/goomba.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/goose.1.zspr b/data/sprites/alttpr/goose.1.zspr deleted file mode 100644 index d2ffb5ba65..0000000000 Binary files a/data/sprites/alttpr/goose.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/grandpoobear.2.zspr b/data/sprites/alttpr/grandpoobear.2.zspr deleted file mode 100644 index 7266368034..0000000000 Binary files a/data/sprites/alttpr/grandpoobear.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/grunclestan.1.zspr b/data/sprites/alttpr/grunclestan.1.zspr deleted file mode 100644 index cf371839f5..0000000000 Binary files a/data/sprites/alttpr/grunclestan.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/guiz.1.zspr b/data/sprites/alttpr/guiz.1.zspr deleted file mode 100644 index 995c08ade7..0000000000 Binary files a/data/sprites/alttpr/guiz.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hardhat_beetle.1.zspr b/data/sprites/alttpr/hardhat_beetle.1.zspr deleted file mode 100644 index 80b63af16f..0000000000 Binary files a/data/sprites/alttpr/hardhat_beetle.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hat-kid.1.zspr b/data/sprites/alttpr/hat-kid.1.zspr deleted file mode 100644 index d03410602c..0000000000 Binary files a/data/sprites/alttpr/hat-kid.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/headlesslink.1.zspr b/data/sprites/alttpr/headlesslink.1.zspr deleted file mode 100644 index 8a9b3ce426..0000000000 Binary files a/data/sprites/alttpr/headlesslink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hello_kitty.1.zspr b/data/sprites/alttpr/hello_kitty.1.zspr deleted file mode 100644 index a2f5df063a..0000000000 Binary files a/data/sprites/alttpr/hello_kitty.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hidari.1.zspr b/data/sprites/alttpr/hidari.1.zspr deleted file mode 100644 index 54a4d0dace..0000000000 Binary files a/data/sprites/alttpr/hidari.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hint_tile.1.zspr b/data/sprites/alttpr/hint_tile.1.zspr deleted file mode 100644 index 9cfd7e90ce..0000000000 Binary files a/data/sprites/alttpr/hint_tile.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hitsuyan.1.zspr b/data/sprites/alttpr/hitsuyan.1.zspr deleted file mode 100644 index 0661577b9b..0000000000 Binary files a/data/sprites/alttpr/hitsuyan.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hoarder-bush.1.zspr b/data/sprites/alttpr/hoarder-bush.1.zspr deleted file mode 100644 index d2adb22751..0000000000 Binary files a/data/sprites/alttpr/hoarder-bush.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hoarder-pot.1.zspr b/data/sprites/alttpr/hoarder-pot.1.zspr deleted file mode 100644 index 717e419991..0000000000 Binary files a/data/sprites/alttpr/hoarder-pot.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hoarder-rock.1.zspr b/data/sprites/alttpr/hoarder-rock.1.zspr deleted file mode 100644 index a93fd1c458..0000000000 Binary files a/data/sprites/alttpr/hoarder-rock.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/homer.1.zspr b/data/sprites/alttpr/homer.1.zspr deleted file mode 100644 index ee8b5f5f51..0000000000 Binary files a/data/sprites/alttpr/homer.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/hyruleknight.1.zspr b/data/sprites/alttpr/hyruleknight.1.zspr deleted file mode 100644 index a8815bc373..0000000000 Binary files a/data/sprites/alttpr/hyruleknight.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ibazly.1.zspr b/data/sprites/alttpr/ibazly.1.zspr deleted file mode 100644 index 01114c9e01..0000000000 Binary files a/data/sprites/alttpr/ibazly.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ignignokt.2.zspr b/data/sprites/alttpr/ignignokt.2.zspr deleted file mode 100644 index f06d07cc61..0000000000 Binary files a/data/sprites/alttpr/ignignokt.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/informant_woman.1.zspr b/data/sprites/alttpr/informant_woman.1.zspr deleted file mode 100644 index 6465a0e9f3..0000000000 Binary files a/data/sprites/alttpr/informant_woman.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/inkling.1.zspr b/data/sprites/alttpr/inkling.1.zspr deleted file mode 100644 index 6b39e4a77b..0000000000 Binary files a/data/sprites/alttpr/inkling.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/invisibleman.1.zspr b/data/sprites/alttpr/invisibleman.1.zspr deleted file mode 100644 index 7993c500c9..0000000000 Binary files a/data/sprites/alttpr/invisibleman.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/jack-frost.1.zspr b/data/sprites/alttpr/jack-frost.1.zspr deleted file mode 100644 index 12dd417a5f..0000000000 Binary files a/data/sprites/alttpr/jack-frost.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/jason_frudnick.1.zspr b/data/sprites/alttpr/jason_frudnick.1.zspr deleted file mode 100644 index 2411759c2a..0000000000 Binary files a/data/sprites/alttpr/jason_frudnick.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/jasp.1.zspr b/data/sprites/alttpr/jasp.1.zspr deleted file mode 100644 index 6dc7449618..0000000000 Binary files a/data/sprites/alttpr/jasp.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/jogurt.1.zspr b/data/sprites/alttpr/jogurt.1.zspr deleted file mode 100644 index b229060c69..0000000000 Binary files a/data/sprites/alttpr/jogurt.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/katsura.1.zspr b/data/sprites/alttpr/katsura.1.zspr deleted file mode 100644 index 422a0fafae..0000000000 Binary files a/data/sprites/alttpr/katsura.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/kecleon.1.zspr b/data/sprites/alttpr/kecleon.1.zspr deleted file mode 100644 index 5e1786ba55..0000000000 Binary files a/data/sprites/alttpr/kecleon.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/kenny_mccormick.1.zspr b/data/sprites/alttpr/kenny_mccormick.1.zspr deleted file mode 100644 index c66a74a586..0000000000 Binary files a/data/sprites/alttpr/kenny_mccormick.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ketchup.1.zspr b/data/sprites/alttpr/ketchup.1.zspr deleted file mode 100644 index 9dbb326c9e..0000000000 Binary files a/data/sprites/alttpr/ketchup.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/kholdstare.1.zspr b/data/sprites/alttpr/kholdstare.1.zspr deleted file mode 100644 index 393a491d25..0000000000 Binary files a/data/sprites/alttpr/kholdstare.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/king_gothalion.1.zspr b/data/sprites/alttpr/king_gothalion.1.zspr deleted file mode 100644 index 65c73f04d4..0000000000 Binary files a/data/sprites/alttpr/king_gothalion.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/king_graham.1.zspr b/data/sprites/alttpr/king_graham.1.zspr deleted file mode 100644 index 28b75cf1a9..0000000000 Binary files a/data/sprites/alttpr/king_graham.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/kirby-meta.1.zspr b/data/sprites/alttpr/kirby-meta.1.zspr deleted file mode 100644 index 9cb132b358..0000000000 Binary files a/data/sprites/alttpr/kirby-meta.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/kore8.1.zspr b/data/sprites/alttpr/kore8.1.zspr deleted file mode 100644 index a1db104ac9..0000000000 Binary files a/data/sprites/alttpr/kore8.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/lakitu.1.zspr b/data/sprites/alttpr/lakitu.1.zspr deleted file mode 100644 index 24d0f12ee2..0000000000 Binary files a/data/sprites/alttpr/lakitu.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/lapras.1.zspr b/data/sprites/alttpr/lapras.1.zspr deleted file mode 100644 index bcec01b2fe..0000000000 Binary files a/data/sprites/alttpr/lapras.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/lest.1.zspr b/data/sprites/alttpr/lest.1.zspr deleted file mode 100644 index 9976492478..0000000000 Binary files a/data/sprites/alttpr/lest.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/lily.1.zspr b/data/sprites/alttpr/lily.1.zspr deleted file mode 100644 index 5cb5d2aa9a..0000000000 Binary files a/data/sprites/alttpr/lily.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/linja.1.zspr b/data/sprites/alttpr/linja.1.zspr deleted file mode 100644 index 414efaf74f..0000000000 Binary files a/data/sprites/alttpr/linja.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/linkhatcolor.1.zspr b/data/sprites/alttpr/linkhatcolor.1.zspr deleted file mode 100644 index af53898dbc..0000000000 Binary files a/data/sprites/alttpr/linkhatcolor.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/linktuniccolor.1.zspr b/data/sprites/alttpr/linktuniccolor.1.zspr deleted file mode 100644 index 305a9f8f9d..0000000000 Binary files a/data/sprites/alttpr/linktuniccolor.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/littlepony.1.zspr b/data/sprites/alttpr/littlepony.1.zspr deleted file mode 100644 index 0ed4b1b1e8..0000000000 Binary files a/data/sprites/alttpr/littlepony.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/locke_merchant.1.zspr b/data/sprites/alttpr/locke_merchant.1.zspr deleted file mode 100644 index bfd87c7da6..0000000000 Binary files a/data/sprites/alttpr/locke_merchant.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/lucario.1.zspr b/data/sprites/alttpr/lucario.1.zspr deleted file mode 100644 index 44ce395e48..0000000000 Binary files a/data/sprites/alttpr/lucario.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/luigi.1.zspr b/data/sprites/alttpr/luigi.1.zspr deleted file mode 100644 index 1a1dc55241..0000000000 Binary files a/data/sprites/alttpr/luigi.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/madeline.1.zspr b/data/sprites/alttpr/madeline.1.zspr deleted file mode 100644 index 8256e6a3b8..0000000000 Binary files a/data/sprites/alttpr/madeline.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/magus.1.zspr b/data/sprites/alttpr/magus.1.zspr deleted file mode 100644 index 171980ef38..0000000000 Binary files a/data/sprites/alttpr/magus.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/maiden.1.zspr b/data/sprites/alttpr/maiden.1.zspr deleted file mode 100644 index e0297901d7..0000000000 Binary files a/data/sprites/alttpr/maiden.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mallow-cat.1.zspr b/data/sprites/alttpr/mallow-cat.1.zspr deleted file mode 100644 index 395684b2bd..0000000000 Binary files a/data/sprites/alttpr/mallow-cat.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mangalink.1.zspr b/data/sprites/alttpr/mangalink.1.zspr deleted file mode 100644 index adb57b9991..0000000000 Binary files a/data/sprites/alttpr/mangalink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/maplequeen.2.zspr b/data/sprites/alttpr/maplequeen.2.zspr deleted file mode 100644 index 35b7deeca8..0000000000 Binary files a/data/sprites/alttpr/maplequeen.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/marin.2.zspr b/data/sprites/alttpr/marin.2.zspr deleted file mode 100644 index 72a06ecf8b..0000000000 Binary files a/data/sprites/alttpr/marin.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mario-classic.2.zspr b/data/sprites/alttpr/mario-classic.2.zspr deleted file mode 100644 index 6443e32749..0000000000 Binary files a/data/sprites/alttpr/mario-classic.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mario_tanooki.1.zspr b/data/sprites/alttpr/mario_tanooki.1.zspr deleted file mode 100644 index 255350dd8c..0000000000 Binary files a/data/sprites/alttpr/mario_tanooki.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mariocappy.1.zspr b/data/sprites/alttpr/mariocappy.1.zspr deleted file mode 100644 index b888396d2f..0000000000 Binary files a/data/sprites/alttpr/mariocappy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/marisa.1.zspr b/data/sprites/alttpr/marisa.1.zspr deleted file mode 100644 index 16b2a803f4..0000000000 Binary files a/data/sprites/alttpr/marisa.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/matthias.1.zspr b/data/sprites/alttpr/matthias.1.zspr deleted file mode 100644 index 062dae6d8c..0000000000 Binary files a/data/sprites/alttpr/matthias.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/meatwad.1.zspr b/data/sprites/alttpr/meatwad.1.zspr deleted file mode 100644 index a09a4adf2e..0000000000 Binary files a/data/sprites/alttpr/meatwad.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/medallions.1.zspr b/data/sprites/alttpr/medallions.1.zspr deleted file mode 100644 index dc4b04d170..0000000000 Binary files a/data/sprites/alttpr/medallions.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/medli.1.zspr b/data/sprites/alttpr/medli.1.zspr deleted file mode 100644 index 59284a366d..0000000000 Binary files a/data/sprites/alttpr/medli.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/megaman-x.2.zspr b/data/sprites/alttpr/megaman-x.2.zspr deleted file mode 100644 index ffe75595ab..0000000000 Binary files a/data/sprites/alttpr/megaman-x.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/metroid.1.zspr b/data/sprites/alttpr/metroid.1.zspr deleted file mode 100644 index d81187cb69..0000000000 Binary files a/data/sprites/alttpr/metroid.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mew.1.zspr b/data/sprites/alttpr/mew.1.zspr deleted file mode 100644 index a06dc8d6df..0000000000 Binary files a/data/sprites/alttpr/mew.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mike-jones.2.zspr b/data/sprites/alttpr/mike-jones.2.zspr deleted file mode 100644 index 550fb213d1..0000000000 Binary files a/data/sprites/alttpr/mike-jones.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/minish_link.1.zspr b/data/sprites/alttpr/minish_link.1.zspr deleted file mode 100644 index 4b342c1acb..0000000000 Binary files a/data/sprites/alttpr/minish_link.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/minishcaplink.2.zspr b/data/sprites/alttpr/minishcaplink.2.zspr deleted file mode 100644 index aaca256bdc..0000000000 Binary files a/data/sprites/alttpr/minishcaplink.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/missingno.1.zspr b/data/sprites/alttpr/missingno.1.zspr deleted file mode 100644 index 68e61b9b02..0000000000 Binary files a/data/sprites/alttpr/missingno.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/modernlink.1.zspr b/data/sprites/alttpr/modernlink.1.zspr deleted file mode 100644 index 6d5e68a4a5..0000000000 Binary files a/data/sprites/alttpr/modernlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mog.2.zspr b/data/sprites/alttpr/mog.2.zspr deleted file mode 100644 index a6ed2225ec..0000000000 Binary files a/data/sprites/alttpr/mog.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/momiji.1.zspr b/data/sprites/alttpr/momiji.1.zspr deleted file mode 100644 index 86a18586e3..0000000000 Binary files a/data/sprites/alttpr/momiji.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/moosh.1.zspr b/data/sprites/alttpr/moosh.1.zspr deleted file mode 100644 index 0a1e167ae2..0000000000 Binary files a/data/sprites/alttpr/moosh.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mouse.1.zspr b/data/sprites/alttpr/mouse.1.zspr deleted file mode 100644 index 16ba884d92..0000000000 Binary files a/data/sprites/alttpr/mouse.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ms-paintdog.1.zspr b/data/sprites/alttpr/ms-paintdog.1.zspr deleted file mode 100644 index 75f5f54127..0000000000 Binary files a/data/sprites/alttpr/ms-paintdog.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/mushy.1.zspr b/data/sprites/alttpr/mushy.1.zspr deleted file mode 100644 index a6c924a50f..0000000000 Binary files a/data/sprites/alttpr/mushy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/naturelink.1.zspr b/data/sprites/alttpr/naturelink.1.zspr deleted file mode 100644 index bdfd0efb95..0000000000 Binary files a/data/sprites/alttpr/naturelink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/navi.1.zspr b/data/sprites/alttpr/navi.1.zspr deleted file mode 100644 index 4621bf4a04..0000000000 Binary files a/data/sprites/alttpr/navi.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/navirou.1.zspr b/data/sprites/alttpr/navirou.1.zspr deleted file mode 100644 index 9da7e76ed2..0000000000 Binary files a/data/sprites/alttpr/navirou.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ned-flanders.1.zspr b/data/sprites/alttpr/ned-flanders.1.zspr deleted file mode 100644 index 78ed5bc40c..0000000000 Binary files a/data/sprites/alttpr/ned-flanders.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/negativelink.1.zspr b/data/sprites/alttpr/negativelink.1.zspr deleted file mode 100644 index a3dd15668b..0000000000 Binary files a/data/sprites/alttpr/negativelink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/neosad.1.zspr b/data/sprites/alttpr/neosad.1.zspr deleted file mode 100644 index 7e95d7f72c..0000000000 Binary files a/data/sprites/alttpr/neosad.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/neslink.1.zspr b/data/sprites/alttpr/neslink.1.zspr deleted file mode 100644 index 805b316263..0000000000 Binary files a/data/sprites/alttpr/neslink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ness.1.zspr b/data/sprites/alttpr/ness.1.zspr deleted file mode 100644 index b8b3de81e2..0000000000 Binary files a/data/sprites/alttpr/ness.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/nia.1.zspr b/data/sprites/alttpr/nia.1.zspr deleted file mode 100644 index 5d01ba4bd8..0000000000 Binary files a/data/sprites/alttpr/nia.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/niko.1.zspr b/data/sprites/alttpr/niko.1.zspr deleted file mode 100644 index 5d39e6bbaa..0000000000 Binary files a/data/sprites/alttpr/niko.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/oldman.2.zspr b/data/sprites/alttpr/oldman.2.zspr deleted file mode 100644 index 1d47cdacc9..0000000000 Binary files a/data/sprites/alttpr/oldman.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ori.2.zspr b/data/sprites/alttpr/ori.2.zspr deleted file mode 100644 index 10c1e462c6..0000000000 Binary files a/data/sprites/alttpr/ori.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/outlinelink.1.zspr b/data/sprites/alttpr/outlinelink.1.zspr deleted file mode 100644 index 50ae98bca3..0000000000 Binary files a/data/sprites/alttpr/outlinelink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/parallelworldslink.1.zspr b/data/sprites/alttpr/parallelworldslink.1.zspr deleted file mode 100644 index 71a9bdc1d4..0000000000 Binary files a/data/sprites/alttpr/parallelworldslink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/paula.1.zspr b/data/sprites/alttpr/paula.1.zspr deleted file mode 100644 index 657752ea29..0000000000 Binary files a/data/sprites/alttpr/paula.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/peach.1.zspr b/data/sprites/alttpr/peach.1.zspr deleted file mode 100644 index 7973f95299..0000000000 Binary files a/data/sprites/alttpr/peach.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/penguinlink.1.zspr b/data/sprites/alttpr/penguinlink.1.zspr deleted file mode 100644 index 2fe01e49ff..0000000000 Binary files a/data/sprites/alttpr/penguinlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pete.1.zspr b/data/sprites/alttpr/pete.1.zspr deleted file mode 100644 index a3135615bb..0000000000 Binary files a/data/sprites/alttpr/pete.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/phoenix-wright.1.zspr b/data/sprites/alttpr/phoenix-wright.1.zspr deleted file mode 100644 index d7cb0be2ee..0000000000 Binary files a/data/sprites/alttpr/phoenix-wright.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pikachu.1.zspr b/data/sprites/alttpr/pikachu.1.zspr deleted file mode 100644 index 0b8a88c48b..0000000000 Binary files a/data/sprites/alttpr/pikachu.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pinkribbonlink.2.zspr b/data/sprites/alttpr/pinkribbonlink.2.zspr deleted file mode 100644 index ba516f1854..0000000000 Binary files a/data/sprites/alttpr/pinkribbonlink.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/piranha_plant.1.zspr b/data/sprites/alttpr/piranha_plant.1.zspr deleted file mode 100644 index 59bf4d0d48..0000000000 Binary files a/data/sprites/alttpr/piranha_plant.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/plagueknight.1.zspr b/data/sprites/alttpr/plagueknight.1.zspr deleted file mode 100644 index 258bed7b80..0000000000 Binary files a/data/sprites/alttpr/plagueknight.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pokey.1.zspr b/data/sprites/alttpr/pokey.1.zspr deleted file mode 100644 index 4de17faf53..0000000000 Binary files a/data/sprites/alttpr/pokey.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/popoi.1.zspr b/data/sprites/alttpr/popoi.1.zspr deleted file mode 100644 index 663d4dc147..0000000000 Binary files a/data/sprites/alttpr/popoi.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/poppy.1.zspr b/data/sprites/alttpr/poppy.1.zspr deleted file mode 100644 index 80d4ca69ef..0000000000 Binary files a/data/sprites/alttpr/poppy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/porg_knight.1.zspr b/data/sprites/alttpr/porg_knight.1.zspr deleted file mode 100644 index 4d6f96351a..0000000000 Binary files a/data/sprites/alttpr/porg_knight.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/powerpuff_girl.1.zspr b/data/sprites/alttpr/powerpuff_girl.1.zspr deleted file mode 100644 index fbf3c69467..0000000000 Binary files a/data/sprites/alttpr/powerpuff_girl.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pridelink.2.zspr b/data/sprites/alttpr/pridelink.2.zspr deleted file mode 100644 index 662310133a..0000000000 Binary files a/data/sprites/alttpr/pridelink.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/primm.1.zspr b/data/sprites/alttpr/primm.1.zspr deleted file mode 100644 index e9ff2d0566..0000000000 Binary files a/data/sprites/alttpr/primm.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/princess_bubblegum.1.zspr b/data/sprites/alttpr/princess_bubblegum.1.zspr deleted file mode 100644 index c46dcc0fa2..0000000000 Binary files a/data/sprites/alttpr/princess_bubblegum.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/psyduck.2.zspr b/data/sprites/alttpr/psyduck.2.zspr deleted file mode 100644 index c9e17117d4..0000000000 Binary files a/data/sprites/alttpr/psyduck.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pug.1.zspr b/data/sprites/alttpr/pug.1.zspr deleted file mode 100644 index 60692711d1..0000000000 Binary files a/data/sprites/alttpr/pug.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/purplechest-bottle.1.zspr b/data/sprites/alttpr/purplechest-bottle.1.zspr deleted file mode 100644 index 8daed4d68f..0000000000 Binary files a/data/sprites/alttpr/purplechest-bottle.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/pyro.1.zspr b/data/sprites/alttpr/pyro.1.zspr deleted file mode 100644 index 9037c8e452..0000000000 Binary files a/data/sprites/alttpr/pyro.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rainbowlink.1.zspr b/data/sprites/alttpr/rainbowlink.1.zspr deleted file mode 100644 index bc8443f9d7..0000000000 Binary files a/data/sprites/alttpr/rainbowlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/remeer.1.zspr b/data/sprites/alttpr/remeer.1.zspr deleted file mode 100644 index 8d7f245aa9..0000000000 Binary files a/data/sprites/alttpr/remeer.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rick.1.zspr b/data/sprites/alttpr/rick.1.zspr deleted file mode 100644 index 93a163f669..0000000000 Binary files a/data/sprites/alttpr/rick.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/robotlink.1.zspr b/data/sprites/alttpr/robotlink.1.zspr deleted file mode 100644 index 8a1eed43f6..0000000000 Binary files a/data/sprites/alttpr/robotlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rocko.1.zspr b/data/sprites/alttpr/rocko.1.zspr deleted file mode 100644 index ab34f63576..0000000000 Binary files a/data/sprites/alttpr/rocko.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rottytops.1.zspr b/data/sprites/alttpr/rottytops.1.zspr deleted file mode 100644 index d4007ffbd5..0000000000 Binary files a/data/sprites/alttpr/rottytops.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/roykoopa.1.zspr b/data/sprites/alttpr/roykoopa.1.zspr deleted file mode 100644 index e1f9699ff1..0000000000 Binary files a/data/sprites/alttpr/roykoopa.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rumia.1.zspr b/data/sprites/alttpr/rumia.1.zspr deleted file mode 100644 index dc037ae201..0000000000 Binary files a/data/sprites/alttpr/rumia.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/rydia.1.zspr b/data/sprites/alttpr/rydia.1.zspr deleted file mode 100644 index ff98ab5617..0000000000 Binary files a/data/sprites/alttpr/rydia.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ryu.1.zspr b/data/sprites/alttpr/ryu.1.zspr deleted file mode 100644 index 5c6d541156..0000000000 Binary files a/data/sprites/alttpr/ryu.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sailormoon.1.zspr b/data/sprites/alttpr/sailormoon.1.zspr deleted file mode 100644 index 1120d3f42b..0000000000 Binary files a/data/sprites/alttpr/sailormoon.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/saitama.1.zspr b/data/sprites/alttpr/saitama.1.zspr deleted file mode 100644 index acd9170d09..0000000000 Binary files a/data/sprites/alttpr/saitama.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/samus-sm.1.zspr b/data/sprites/alttpr/samus-sm.1.zspr deleted file mode 100644 index c8fde01b21..0000000000 Binary files a/data/sprites/alttpr/samus-sm.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/samus.2.zspr b/data/sprites/alttpr/samus.2.zspr deleted file mode 100644 index 81b0912fa9..0000000000 Binary files a/data/sprites/alttpr/samus.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/samus_classic.1.zspr b/data/sprites/alttpr/samus_classic.1.zspr deleted file mode 100644 index 6559e25ce6..0000000000 Binary files a/data/sprites/alttpr/samus_classic.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/santalink.2.zspr b/data/sprites/alttpr/santalink.2.zspr deleted file mode 100644 index 0e78fedb34..0000000000 Binary files a/data/sprites/alttpr/santalink.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/scholar.1.zspr b/data/sprites/alttpr/scholar.1.zspr deleted file mode 100644 index bf697f16f4..0000000000 Binary files a/data/sprites/alttpr/scholar.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/selan.1.zspr b/data/sprites/alttpr/selan.1.zspr deleted file mode 100644 index eb3b0318d3..0000000000 Binary files a/data/sprites/alttpr/selan.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sevens1ns.1.zspr b/data/sprites/alttpr/sevens1ns.1.zspr deleted file mode 100644 index d59a1b529f..0000000000 Binary files a/data/sprites/alttpr/sevens1ns.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shadow.1.zspr b/data/sprites/alttpr/shadow.1.zspr deleted file mode 100644 index fcd0d49b60..0000000000 Binary files a/data/sprites/alttpr/shadow.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shadowsaku.2.zspr b/data/sprites/alttpr/shadowsaku.2.zspr deleted file mode 100644 index 8972f9f266..0000000000 Binary files a/data/sprites/alttpr/shadowsaku.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shantae.1.zspr b/data/sprites/alttpr/shantae.1.zspr deleted file mode 100644 index 03a1c7b9a7..0000000000 Binary files a/data/sprites/alttpr/shantae.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shuppet.1.zspr b/data/sprites/alttpr/shuppet.1.zspr deleted file mode 100644 index 55a51ae994..0000000000 Binary files a/data/sprites/alttpr/shuppet.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shy-gal.1.zspr b/data/sprites/alttpr/shy-gal.1.zspr deleted file mode 100644 index b86b27bc19..0000000000 Binary files a/data/sprites/alttpr/shy-gal.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/shy-guy.1.zspr b/data/sprites/alttpr/shy-guy.1.zspr deleted file mode 100644 index 43ee0fe47c..0000000000 Binary files a/data/sprites/alttpr/shy-guy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sighn_waive.1.zspr b/data/sprites/alttpr/sighn_waive.1.zspr deleted file mode 100644 index d961dc4d56..0000000000 Binary files a/data/sprites/alttpr/sighn_waive.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/snes-controller.1.zspr b/data/sprites/alttpr/snes-controller.1.zspr deleted file mode 100644 index 5dd70f3943..0000000000 Binary files a/data/sprites/alttpr/snes-controller.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sodacan.1.zspr b/data/sprites/alttpr/sodacan.1.zspr deleted file mode 100644 index 93e6fb1ec2..0000000000 Binary files a/data/sprites/alttpr/sodacan.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/solaire.1.zspr b/data/sprites/alttpr/solaire.1.zspr deleted file mode 100644 index e216a7d922..0000000000 Binary files a/data/sprites/alttpr/solaire.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/soldiersprite.1.zspr b/data/sprites/alttpr/soldiersprite.1.zspr deleted file mode 100644 index d5e8ee356d..0000000000 Binary files a/data/sprites/alttpr/soldiersprite.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sonic.1.zspr b/data/sprites/alttpr/sonic.1.zspr deleted file mode 100644 index 557242192c..0000000000 Binary files a/data/sprites/alttpr/sonic.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sora.1.zspr b/data/sprites/alttpr/sora.1.zspr deleted file mode 100644 index c8d656fd06..0000000000 Binary files a/data/sprites/alttpr/sora.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/sora_kh1.1.zspr b/data/sprites/alttpr/sora_kh1.1.zspr deleted file mode 100644 index e77c922d20..0000000000 Binary files a/data/sprites/alttpr/sora_kh1.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/squall.1.zspr b/data/sprites/alttpr/squall.1.zspr deleted file mode 100644 index b9cd9556b6..0000000000 Binary files a/data/sprites/alttpr/squall.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/squirrel.1.zspr b/data/sprites/alttpr/squirrel.1.zspr deleted file mode 100644 index 64e399a127..0000000000 Binary files a/data/sprites/alttpr/squirrel.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/squirtle.1.zspr b/data/sprites/alttpr/squirtle.1.zspr deleted file mode 100644 index 274bf1c760..0000000000 Binary files a/data/sprites/alttpr/squirtle.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/stalfos.1.zspr b/data/sprites/alttpr/stalfos.1.zspr deleted file mode 100644 index d4787a3b03..0000000000 Binary files a/data/sprites/alttpr/stalfos.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/stan.1.zspr b/data/sprites/alttpr/stan.1.zspr deleted file mode 100644 index 5fd3eb1183..0000000000 Binary files a/data/sprites/alttpr/stan.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/staticlink.1.zspr b/data/sprites/alttpr/staticlink.1.zspr deleted file mode 100644 index d0f1bc0686..0000000000 Binary files a/data/sprites/alttpr/staticlink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/stick_man.1.zspr b/data/sprites/alttpr/stick_man.1.zspr deleted file mode 100644 index b891586f4b..0000000000 Binary files a/data/sprites/alttpr/stick_man.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/superbomb.1.zspr b/data/sprites/alttpr/superbomb.1.zspr deleted file mode 100644 index 1ed38ae3ec..0000000000 Binary files a/data/sprites/alttpr/superbomb.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/superbunny.2.zspr b/data/sprites/alttpr/superbunny.2.zspr deleted file mode 100644 index b842d1c35f..0000000000 Binary files a/data/sprites/alttpr/superbunny.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/supermeatboy.1.zspr b/data/sprites/alttpr/supermeatboy.1.zspr deleted file mode 100644 index ad4368bb5f..0000000000 Binary files a/data/sprites/alttpr/supermeatboy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/swatchy.1.zspr b/data/sprites/alttpr/swatchy.1.zspr deleted file mode 100644 index 46795e9b6b..0000000000 Binary files a/data/sprites/alttpr/swatchy.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tasbot.1.zspr b/data/sprites/alttpr/tasbot.1.zspr deleted file mode 100644 index b7278587ed..0000000000 Binary files a/data/sprites/alttpr/tasbot.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/teatime.1.zspr b/data/sprites/alttpr/teatime.1.zspr deleted file mode 100644 index 8953bc79b8..0000000000 Binary files a/data/sprites/alttpr/teatime.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/terra.1.zspr b/data/sprites/alttpr/terra.1.zspr deleted file mode 100644 index e24ca87aad..0000000000 Binary files a/data/sprites/alttpr/terra.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tetra.1.zspr b/data/sprites/alttpr/tetra.1.zspr deleted file mode 100644 index 77525f08a9..0000000000 Binary files a/data/sprites/alttpr/tetra.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tgh.1.zspr b/data/sprites/alttpr/tgh.1.zspr deleted file mode 100644 index 929b87051f..0000000000 Binary files a/data/sprites/alttpr/tgh.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/thief.1.zspr b/data/sprites/alttpr/thief.1.zspr deleted file mode 100644 index b6b0ffefc1..0000000000 Binary files a/data/sprites/alttpr/thief.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/thomcrow.1.zspr b/data/sprites/alttpr/thomcrow.1.zspr deleted file mode 100644 index 81bba95df1..0000000000 Binary files a/data/sprites/alttpr/thomcrow.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tile.2.zspr b/data/sprites/alttpr/tile.2.zspr deleted file mode 100644 index 38332bb06f..0000000000 Binary files a/data/sprites/alttpr/tile.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tingle.1.zspr b/data/sprites/alttpr/tingle.1.zspr deleted file mode 100644 index 9a53f8d21e..0000000000 Binary files a/data/sprites/alttpr/tingle.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/tmnt.1.zspr b/data/sprites/alttpr/tmnt.1.zspr deleted file mode 100644 index 8f01c1db46..0000000000 Binary files a/data/sprites/alttpr/tmnt.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/toad.2.zspr b/data/sprites/alttpr/toad.2.zspr deleted file mode 100644 index 6abca2d71e..0000000000 Binary files a/data/sprites/alttpr/toad.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/toadette.2.zspr b/data/sprites/alttpr/toadette.2.zspr deleted file mode 100644 index 8c6498b2d7..0000000000 Binary files a/data/sprites/alttpr/toadette.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/toadette_captain.1.zspr b/data/sprites/alttpr/toadette_captain.1.zspr deleted file mode 100644 index e69f74a71c..0000000000 Binary files a/data/sprites/alttpr/toadette_captain.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/totem-links.1.zspr b/data/sprites/alttpr/totem-links.1.zspr deleted file mode 100644 index e4ac6abcc5..0000000000 Binary files a/data/sprites/alttpr/totem-links.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/trogdor.1.zspr b/data/sprites/alttpr/trogdor.1.zspr deleted file mode 100644 index b37191acc3..0000000000 Binary files a/data/sprites/alttpr/trogdor.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/twilightprincesszelda.2.zspr b/data/sprites/alttpr/twilightprincesszelda.2.zspr deleted file mode 100644 index 2487f44a5d..0000000000 Binary files a/data/sprites/alttpr/twilightprincesszelda.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/two_faced.1.zspr b/data/sprites/alttpr/two_faced.1.zspr deleted file mode 100644 index d504c321ad..0000000000 Binary files a/data/sprites/alttpr/two_faced.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ty.1.zspr b/data/sprites/alttpr/ty.1.zspr deleted file mode 100644 index 1091b298d3..0000000000 Binary files a/data/sprites/alttpr/ty.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/ultros.1.zspr b/data/sprites/alttpr/ultros.1.zspr deleted file mode 100644 index bd312843f7..0000000000 Binary files a/data/sprites/alttpr/ultros.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/valeera.1.zspr b/data/sprites/alttpr/valeera.1.zspr deleted file mode 100644 index 090a6631e2..0000000000 Binary files a/data/sprites/alttpr/valeera.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vanillalink.1.zspr b/data/sprites/alttpr/vanillalink.1.zspr deleted file mode 100644 index 409171fab1..0000000000 Binary files a/data/sprites/alttpr/vanillalink.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vaporeon.1.zspr b/data/sprites/alttpr/vaporeon.1.zspr deleted file mode 100644 index 5537272271..0000000000 Binary files a/data/sprites/alttpr/vaporeon.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vegeta.1.zspr b/data/sprites/alttpr/vegeta.1.zspr deleted file mode 100644 index b4f4601935..0000000000 Binary files a/data/sprites/alttpr/vegeta.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vera.1.zspr b/data/sprites/alttpr/vera.1.zspr deleted file mode 100644 index b891436506..0000000000 Binary files a/data/sprites/alttpr/vera.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vitreous.1.zspr b/data/sprites/alttpr/vitreous.1.zspr deleted file mode 100644 index 947eff3017..0000000000 Binary files a/data/sprites/alttpr/vitreous.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vivi.1.zspr b/data/sprites/alttpr/vivi.1.zspr deleted file mode 100644 index a7ad1a5f84..0000000000 Binary files a/data/sprites/alttpr/vivi.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/vivian.1.zspr b/data/sprites/alttpr/vivian.1.zspr deleted file mode 100644 index 9de1061f87..0000000000 Binary files a/data/sprites/alttpr/vivian.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/wario.1.zspr b/data/sprites/alttpr/wario.1.zspr deleted file mode 100644 index f1a5aab774..0000000000 Binary files a/data/sprites/alttpr/wario.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/will.1.zspr b/data/sprites/alttpr/will.1.zspr deleted file mode 100644 index d379496958..0000000000 Binary files a/data/sprites/alttpr/will.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/wizzrobe.2.zspr b/data/sprites/alttpr/wizzrobe.2.zspr deleted file mode 100644 index f79195d239..0000000000 Binary files a/data/sprites/alttpr/wizzrobe.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/wolf_link.1.zspr b/data/sprites/alttpr/wolf_link.1.zspr deleted file mode 100644 index 5ee07dcb19..0000000000 Binary files a/data/sprites/alttpr/wolf_link.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/wolf_link_tp.1.zspr b/data/sprites/alttpr/wolf_link_tp.1.zspr deleted file mode 100644 index 9627cd73d4..0000000000 Binary files a/data/sprites/alttpr/wolf_link_tp.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/yoshi.1.zspr b/data/sprites/alttpr/yoshi.1.zspr deleted file mode 100644 index 189ea3901d..0000000000 Binary files a/data/sprites/alttpr/yoshi.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/yunica.1.zspr b/data/sprites/alttpr/yunica.1.zspr deleted file mode 100644 index 57f1f4169c..0000000000 Binary files a/data/sprites/alttpr/yunica.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zandra.1.zspr b/data/sprites/alttpr/zandra.1.zspr deleted file mode 100644 index d7e5012c8b..0000000000 Binary files a/data/sprites/alttpr/zandra.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zebraunicorn.1.zspr b/data/sprites/alttpr/zebraunicorn.1.zspr deleted file mode 100644 index c06130ff7a..0000000000 Binary files a/data/sprites/alttpr/zebraunicorn.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zeck.1.zspr b/data/sprites/alttpr/zeck.1.zspr deleted file mode 100644 index 630acd1ac0..0000000000 Binary files a/data/sprites/alttpr/zeck.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zelda.1.zspr b/data/sprites/alttpr/zelda.1.zspr deleted file mode 100644 index 26ba1a05f9..0000000000 Binary files a/data/sprites/alttpr/zelda.1.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zerosuitsamus.2.zspr b/data/sprites/alttpr/zerosuitsamus.2.zspr deleted file mode 100644 index 0e5a7d1790..0000000000 Binary files a/data/sprites/alttpr/zerosuitsamus.2.zspr and /dev/null differ diff --git a/data/sprites/alttpr/zora.2.zspr b/data/sprites/alttpr/zora.2.zspr deleted file mode 100644 index 1ca568e113..0000000000 Binary files a/data/sprites/alttpr/zora.2.zspr and /dev/null differ diff --git a/host.yaml b/host.yaml index 4cdc517435..4968083c18 100644 --- a/host.yaml +++ b/host.yaml @@ -22,8 +22,6 @@ server_options: loglevel: "info" # Allows for clients to log on and manage the server. If this is null, no remote administration is possible. server_password: null - # Automatically forward the port that is used, then close that port after 24 hours - port_forward: false # Disallow !getitem. Old /getitem cannot be blocked this way disable_item_cheat: false # Client hint system @@ -57,10 +55,15 @@ multi_mystery_options: # Teams # Note that there is currently no way to supply names for teams 2+ through MultiMystery teams: 1 - # Location of your Enemizer CLI, available here: https://github.com/Bonta0/Enemizer/releases + # Location of your Enemizer CLI, available here: https://github.com/Ijwu/Enemizer/releases enemizer_path: "EnemizerCLI/EnemizerCLI.Core.exe" # Folder from which the player yaml files are pulled from player_files_path: "Players" + #amount of players, 0 to infer from player files + players: 0 + # general weights file, within the stated player_files_path location + # gets used if players is higher than the amount of per-player files found to fill remaining slots + weights_file_path: "weights.yaml" # Meta file name, within the stated player_files_path location meta_file_path: "meta.yaml" # Automatically launches {player_name}.yaml's ROM file using the OS's default program once generation completes. (likely your emulator) @@ -94,5 +97,5 @@ multi_mystery_options: # 2 -> 7z is recommended for roms. All of them get the job done. # 3 -> bz2 zip_format: 1 - # Create roms flagged as race roms + # Create encrypted race roms race: 0 diff --git a/inno_setup.iss b/inno_setup.iss index 12d38cf514..675fddb77e 100644 --- a/inno_setup.iss +++ b/inno_setup.iss @@ -1,4 +1,4 @@ -#define sourcepath "build\exe.win-amd64-3.8\" +#define sourcepath "build\exe.win-amd64-3.9\" #define MyAppName "BerserkerMultiWorld" #define MyAppExeName "BerserkerMultiClient.exe" #define MyAppIcon "icon.ico" @@ -40,7 +40,7 @@ NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-mod [Files] Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external -Source: "{#sourcepath}*"; Excludes: "*.key, *.log, *.hpkey"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall ; NOTE: Don't use "Flags: ignoreversion" on any shared system files @@ -52,6 +52,7 @@ Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: [Run] Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; Check: IsVCRedist64BitNeeded; StatusMsg: "Installing VC++ redistributable..." +Filename: "{app}\BerserkerMultiCreator"; Parameters: "update_sprites"; StatusMsg: "Updating Sprite Library..." [UninstallDelete] Type: dirifempty; Name: "{app}" diff --git a/meta.yaml b/meta.yaml index 3f1afb5693..6642402b4a 100644 --- a/meta.yaml +++ b/meta.yaml @@ -21,9 +21,10 @@ goals: dungeons: 50 # Defeat the boss of all dungeons, including Agahnim's tower and GT (Aga 2) pedestal: 100 # Pull the Triforce from the Master Sword pedestal triforce-hunt: 5 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then turn them in to Murahadala in front of Hyrule Castle - local_triforce_hunt: 10 # Collect 20 of 30 Triforce pieces spread throughout your world, then turn them in to Murahadala in front of Hyrule Castle - ganon_triforce_hunt: 5 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon - local_ganon_triforce_hunt: 20 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon + local_triforce_hunt: 5 # Collect 20 of 30 Triforce pieces spread throughout your world, then turn them in to Murahadala in front of Hyrule Castle + ganon_triforce_hunt: 10 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon + local_ganon_triforce_hunt: 10 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon + ganon_pedestal: 10 # Pull the Master Sword pedestal, then kill Ganon null: 0 # Maintain individual goals mode: standard: 10 @@ -50,4 +51,14 @@ ganon_open: '6': 9 '7': 10 random: 5 # This will mean differing completion times. But leaving it for that surprise effect +triforce_pieces_mode: #Determine how to calculate the extra available triforce pieces. + extra: 0 # available = triforce_pieces_extra + triforce_pieces_required + percentage: 0 # available = (triforce_pieces_percentage /100) * triforce_pieces_required + available: 50 # available = triforce_pieces_available +triforce_pieces_available: # Set to how many triforces pieces are available to collect in the world. Default is 30. Max is 90, Min is 1 + # Format "pieces: chance" + 30: 50 +triforce_pieces_required: # Set to how many out of X triforce pieces you need to win the game in a triforce hunt. Default is 20. Max is 90, Min is 1 + # Format "pieces: chance" + 25: 50 # Do not use meta rom options at this time \ No newline at end of file diff --git a/playerSettings.yaml b/playerSettings.yaml index 83df46e2dc..469a96dea1 100644 --- a/playerSettings.yaml +++ b/playerSettings.yaml @@ -107,7 +107,7 @@ triforce_pieces_extra: # Set to how many extra triforces pieces are available to 10: 50 15: 0 20: 0 -triforce_pieces_percentage: # Set to how many extra triforces pieces according to a percentage of the required ones, are available to collect in the world. +triforce_pieces_percentage: # Set to how many triforce pieces according to a percentage of the required ones, are available to collect in the world. # Format "pieces: chance" 100: 0 #No extra 150: 50 #Half the required will be added as extra @@ -165,7 +165,6 @@ item_pool: normal: 50 # Item availability remains unchanged from vanilla game hard: 0 # Reduced upgrade availability (max: 14 hearts, blue mail, tempered sword, fire shield, no silvers unless swordless) expert: 0 # Minimum upgrade availability (max: 8 hearts, green mail, master sword, fighter shield, no silvers unless swordless) - crowd_control: 0 # Sets up the item pool for the crowd control extension. Do not use it without crowd control item_functionality: easy: 0 # Allow Hammer to damage ganon, Allow Hammer tablet collection, Allow swordless medallion use everywhere. normal: 50 # Vanilla item functionality @@ -254,6 +253,11 @@ green_clock_time: # For all timer modes, the amount of time in minutes to gain o # - "Small Keys" # - "Big Keys" # Can be uncommented to use it +# non_local_items: # Force certain items to appear outside your world only, always across the multiworld. Recognizes some group names, like "Swords" +# - "Moon Pearl" +# - "Small Keys" +# - "Big Keys" +# Can be uncommented to use it # startinventory: # Begin the file with the listed items/upgrades # Pegasus Boots: on # Bomb Upgrade (+10): 4 @@ -305,8 +309,11 @@ intensity: # Only available if the host uses the doors branch, it is ignored oth 2: 0 # And shuffles open edges and straight staircases 3: 0 # And shuffles dungeon lobbies random: 0 # Picks one of those at random +key_drop_shuffle: # Only available if the host uses the doors branch, it is ignored otherwise + on: 0 # Enables the small keys dropped by enemies or under pots, and the big key dropped by the Ball & Chain guard to be shuffled into the pool. This extends the number of checks to 249. + off: 50 experimental: # Only available if the host uses the doors branch, it is ignored otherwise - on: 0 # Enables experimental features. Currently, this is just the dungeon keys in chest counter. + on: 0 # Enables experimental features. off: 50 debug: # Only available if the host uses the doors branch, it is ignored otherwise on: 0 # Enables debugging features. Currently, these are the Item collection counter. (overwrites total triforce pieces) and Castle Gate closed indicator. diff --git a/setup.py b/setup.py index 03257fa863..2d66383e98 100644 --- a/setup.py +++ b/setup.py @@ -128,6 +128,9 @@ else: qusb2sneslog = buildfolder / "QUsb2Snes" / "log.txt" if os.path.exists(qusb2sneslog): os.remove(qusb2sneslog) +qusb2snesconfig = buildfolder / "QUsb2Snes" / "config.ini" +if os.path.exists(qusb2snesconfig): + os.remove(qusb2snesconfig) if signtool: for exe in exes: