diff --git a/.gitignore b/.gitignore index ecd316cb..1b54572f 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 794bd6c3..661381a9 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 28a72d9c..f26c669b 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 b47e7e51..dd7b24e2 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 f4e7156a..7d018c98 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 222c367c..5c9ab56c 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 9051f93a..1212f6e0 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 aa3a6220..94a145ab 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 0bebfda6..c0542076 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 84f449fc..e58dcdaf 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 22134dc9..3c98708c 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 e51ba534..bc84dd57 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 7f97cdd6..5503a61c 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 2857521a..d74c9973 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 37d84713..d2d74e6e 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 b86060bc..04889a0f 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 ba665065..1c97abe1 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 c2d893e7..fe7d726d 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 8b6f10dd..4942dfef 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 00000000..abe4aeb2 --- /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 00000000..4b5ea710 --- /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 4a6ffc36..4831cd79 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 b26e2c7b..d8c78ee0 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 d5e0f2b8..77bd6f2f 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 52aa607d..f7a97f65 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 dbbbbc75..e6ee539f 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 379e18a4..b6e7747f 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 edcec214..d4ce6a60 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 8ed7084b..564edb17 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 00000000..d6b7ef32 --- /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 4537afa8..00000000 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 7a944113..00000000 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 526990c5..00000000 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 da8210a9..00000000 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 c23d9d83..00000000 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 4c673acd..00000000 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 79aee561..00000000 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 b0fd4760..00000000 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 916b036a..00000000 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 2064009d..00000000 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 a4db3020..00000000 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 b9fb1346..00000000 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 f75af2b2..00000000 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 5b3288f8..00000000 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 a4a1e9c0..00000000 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 8d8d2079..00000000 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 265d2e1a..00000000 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 eab4854e..00000000 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 d6d86bb6..00000000 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 54c49747..00000000 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 d9b56288..00000000 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 e9aeb31a..00000000 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 57f4918c..00000000 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 25fc0410..00000000 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 a5c5463c..00000000 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 24c74bde..00000000 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 28ca1f9b..00000000 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 630adfa6..00000000 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 1cc256d8..00000000 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 b7926418..00000000 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 013a2207..00000000 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 e335df01..00000000 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 d1afd117..00000000 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 7d00be74..00000000 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 82923751..00000000 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 bbba3b75..00000000 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 5b561b9e..00000000 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 bd066c27..00000000 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 51c32893..00000000 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 05f174f7..00000000 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 2632cb6f..00000000 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 80257f11..00000000 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 69946d73..00000000 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 45a4fa81..00000000 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 3236f799..00000000 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 ac0c1226..00000000 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 babed511..00000000 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 a49545f2..00000000 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 949dbe2e..00000000 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 75de8ab6..00000000 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 73f848c1..00000000 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 b590a2ef..00000000 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 121d5233..00000000 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 4c58f356..00000000 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 2ed39a78..00000000 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 f237de4a..00000000 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 45bc9739..00000000 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 147283ea..00000000 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 1b39b747..00000000 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 de55ebbe..00000000 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 8fd848fd..00000000 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 fe417308..00000000 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 b0d9a95f..00000000 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 88677425..00000000 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 519c278a..00000000 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 fbb15c69..00000000 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 abcda926..00000000 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 3d2e87f7..00000000 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 cc28cd79..00000000 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 1c769e62..00000000 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 2daf7359..00000000 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 37d95ad0..00000000 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 1be94a75..00000000 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 c33c2008..00000000 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 a636dad9..00000000 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 54596847..00000000 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 770b89de..00000000 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 265b197c..00000000 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 9c3a530b..00000000 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 86684e7d..00000000 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 5e1df365..00000000 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 d6eaf433..00000000 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 b43338d5..00000000 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 d521cae3..00000000 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 f5c46d82..00000000 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 9254ff7b..00000000 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 456e64c7..00000000 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 9f78d894..00000000 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 a6adda43..00000000 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 5bb6f548..00000000 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 6ca890e8..00000000 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 858497c7..00000000 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 65b9959d..00000000 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 e98a6d08..00000000 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 3d747a2a..00000000 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 51dd1192..00000000 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 0438682f..00000000 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 d2ffb5ba..00000000 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 72663680..00000000 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 cf371839..00000000 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 995c08ad..00000000 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 80b63af1..00000000 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 d0341060..00000000 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 8a9b3ce4..00000000 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 a2f5df06..00000000 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 54a4d0da..00000000 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 9cfd7e90..00000000 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 0661577b..00000000 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 d2adb227..00000000 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 717e4199..00000000 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 a93fd1c4..00000000 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 ee8b5f5f..00000000 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 a8815bc3..00000000 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 01114c9e..00000000 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 f06d07cc..00000000 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 6465a0e9..00000000 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 6b39e4a7..00000000 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 7993c500..00000000 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 12dd417a..00000000 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 2411759c..00000000 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 6dc74496..00000000 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 b229060c..00000000 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 422a0faf..00000000 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 5e1786ba..00000000 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 c66a74a5..00000000 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 9dbb326c..00000000 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 393a491d..00000000 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 65c73f04..00000000 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 28b75cf1..00000000 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 9cb132b3..00000000 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 a1db104a..00000000 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 24d0f12e..00000000 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 bcec01b2..00000000 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 99764924..00000000 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 5cb5d2aa..00000000 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 414efaf7..00000000 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 af53898d..00000000 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 305a9f8f..00000000 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 0ed4b1b1..00000000 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 bfd87c7d..00000000 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 44ce395e..00000000 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 1a1dc552..00000000 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 8256e6a3..00000000 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 171980ef..00000000 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 e0297901..00000000 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 395684b2..00000000 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 adb57b99..00000000 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 35b7deec..00000000 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 72a06ecf..00000000 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 6443e327..00000000 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 255350dd..00000000 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 b888396d..00000000 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 16b2a803..00000000 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 062dae6d..00000000 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 a09a4adf..00000000 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 dc4b04d1..00000000 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 59284a36..00000000 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 ffe75595..00000000 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 d81187cb..00000000 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 a06dc8d6..00000000 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 550fb213..00000000 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 4b342c1a..00000000 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 aaca256b..00000000 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 68e61b9b..00000000 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 6d5e68a4..00000000 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 a6ed2225..00000000 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 86a18586..00000000 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 0a1e167a..00000000 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 16ba884d..00000000 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 75f5f541..00000000 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 a6c924a5..00000000 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 bdfd0efb..00000000 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 4621bf4a..00000000 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 9da7e76e..00000000 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 78ed5bc4..00000000 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 a3dd1566..00000000 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 7e95d7f7..00000000 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 805b3162..00000000 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 b8b3de81..00000000 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 5d01ba4b..00000000 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 5d39e6bb..00000000 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 1d47cdac..00000000 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 10c1e462..00000000 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 50ae98bc..00000000 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 71a9bdc1..00000000 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 657752ea..00000000 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 7973f952..00000000 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 2fe01e49..00000000 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 a3135615..00000000 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 d7cb0be2..00000000 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 0b8a88c4..00000000 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 ba516f18..00000000 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 59bf4d0d..00000000 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 258bed7b..00000000 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 4de17faf..00000000 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 663d4dc1..00000000 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 80d4ca69..00000000 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 4d6f9635..00000000 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 fbf3c694..00000000 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 66231013..00000000 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 e9ff2d05..00000000 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 c46dcc0f..00000000 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 c9e17117..00000000 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 60692711..00000000 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 8daed4d6..00000000 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 9037c8e4..00000000 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 bc8443f9..00000000 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 8d7f245a..00000000 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 93a163f6..00000000 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 8a1eed43..00000000 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 ab34f635..00000000 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 d4007ffb..00000000 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 e1f9699f..00000000 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 dc037ae2..00000000 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 ff98ab56..00000000 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 5c6d5411..00000000 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 1120d3f4..00000000 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 acd9170d..00000000 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 c8fde01b..00000000 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 81b0912f..00000000 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 6559e25c..00000000 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 0e78fedb..00000000 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 bf697f16..00000000 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 eb3b0318..00000000 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 d59a1b52..00000000 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 fcd0d49b..00000000 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 8972f9f2..00000000 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 03a1c7b9..00000000 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 55a51ae9..00000000 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 b86b27bc..00000000 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 43ee0fe4..00000000 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 d961dc4d..00000000 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 5dd70f39..00000000 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 93e6fb1e..00000000 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 e216a7d9..00000000 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 d5e8ee35..00000000 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 55724219..00000000 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 c8d656fd..00000000 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 e77c922d..00000000 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 b9cd9556..00000000 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 64e399a1..00000000 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 274bf1c7..00000000 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 d4787a3b..00000000 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 5fd3eb11..00000000 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 d0f1bc06..00000000 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 b891586f..00000000 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 1ed38ae3..00000000 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 b842d1c3..00000000 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 ad4368bb..00000000 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 46795e9b..00000000 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 b7278587..00000000 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 8953bc79..00000000 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 e24ca87a..00000000 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 77525f08..00000000 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 929b8705..00000000 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 b6b0ffef..00000000 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 81bba95d..00000000 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 38332bb0..00000000 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 9a53f8d2..00000000 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 8f01c1db..00000000 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 6abca2d7..00000000 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 8c6498b2..00000000 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 e69f74a7..00000000 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 e4ac6abc..00000000 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 b37191ac..00000000 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 2487f44a..00000000 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 d504c321..00000000 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 1091b298..00000000 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 bd312843..00000000 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 090a6631..00000000 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 409171fa..00000000 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 55372722..00000000 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 b4f46019..00000000 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 b8914365..00000000 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 947eff30..00000000 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 a7ad1a5f..00000000 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 9de1061f..00000000 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 f1a5aab7..00000000 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 d3794969..00000000 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 f79195d2..00000000 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 5ee07dcb..00000000 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 9627cd73..00000000 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 189ea390..00000000 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 57f1f416..00000000 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 d7e5012c..00000000 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 c06130ff..00000000 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 630acd1a..00000000 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 26ba1a05..00000000 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 0e5a7d17..00000000 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 1ca568e1..00000000 Binary files a/data/sprites/alttpr/zora.2.zspr and /dev/null differ diff --git a/host.yaml b/host.yaml index 4cdc5174..4968083c 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 12d38cf5..675fddb7 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 3f1afb56..6642402b 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 83df46e2..469a96de 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 03257fa8..2d66383e 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: