diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a90cee26..b12176d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,8 @@ jobs: # os & python versions strategy: matrix: - os-name: [ ubuntu-latest, ubuntu-16.04, macOS-latest, windows-latest ] - python-version: [ 3.7 ] + os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ] + python-version: [ 3.8 ] # needs: [ install-test ] steps: # checkout commit @@ -57,11 +57,11 @@ jobs: # run build-gui.py - name: Build GUI run: | - python ./build-gui.py + python ./source/meta/build-gui.py # run build-dr.py - name: Build DungeonRandomizer run: | - python ./build-dr.py + python ./source/meta/build-dr.py # prepare binary artifacts for later step - name: Prepare Binary Artifacts env: @@ -88,8 +88,8 @@ jobs: strategy: matrix: # install/release on not xenial - os-name: [ ubuntu-latest, macOS-latest, windows-latest ] - python-version: [ 3.7 ] + os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ] + python-version: [ 3.8 ] needs: [ install-build ] steps: @@ -150,9 +150,9 @@ jobs: # os & python versions strategy: matrix: - # release only on bionic + # release only on focal/bionic os-name: [ ubuntu-latest ] - python-version: [ 3.7 ] + python-version: [ 3.8 ] needs: [ install-prepare-release ] steps: diff --git a/BaseClasses.py b/BaseClasses.py index 38a7d7fd..551720bb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -153,9 +153,10 @@ class World(object): self._door_cache[(door.name, door.player)] = door def remove_door(self, door, player): - if (door, player) in self._door_cache.keys(): - del self._door_cache[(door, player)] - self.doors.remove(door) + if (door.name, player) in self._door_cache.keys(): + del self._door_cache[(door.name, player)] + if door in self.doors: + self.doors.remove(door) def get_regions(self, player=None): return self.regions if player is None else self._region_cache[player].values() @@ -1070,7 +1071,7 @@ hook_dir_map = { def hook_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: return hook_dir_map[door.direction] return None @@ -1188,7 +1189,8 @@ class Door(object): # rom properties self.roomIndex = -1 - # 0,1,2 + Direction (N:0, W:3, S:6, E:9) for normal + # 0,1,2 for normal + # 0-7 for ladder # 0-4 for spiral offset thing self.doorIndex = -1 self.layer = -1 # 0 for normal floor, 1 for the inset layer @@ -1219,6 +1221,7 @@ class Door(object): # self.connected = False # combine with Dest? self.dest = None self.blocked = False # Indicates if the door is normally blocked off as an exit. (Sanc door or always closed) + self.blocked_orig = False self.stonewall = False # Indicate that the door cannot be enter until exited (Desert Torches, PoD Eye Statue) self.smallKey = False # There's a small key door on this side self.bigKey = False # There's a big key door on this side @@ -1230,7 +1233,7 @@ class Door(object): self.dead = False self.entrance = entrance - if entrance is not None: + if entrance is not None and not entrance.door: entrance.door = self def getAddress(self): @@ -1238,6 +1241,8 @@ class Door(object): return 0x13A000 + normal_offset_table[self.roomIndex] * 24 + (self.doorIndex + self.direction.value * 3) * 2 elif self.type == DoorType.SpiralStairs: return 0x13B000 + (spiral_offset_table[self.roomIndex] + self.doorIndex) * 4 + elif self.type == DoorType.Ladder: + return 0x13C700 + self.doorIndex * 2 elif self.type == DoorType.Open: base_address = { Direction.North: 0x13C500, @@ -1254,6 +1259,12 @@ class Door(object): if src.type == DoorType.StraightStairs: bitmask += 0x40 return [self.roomIndex, bitmask + self.doorIndex] + if self.type == DoorType.Ladder: + bitmask = 4 * (self.layer ^ 1 if src.toggle else self.layer) + bitmask += 0x08 * self.doorIndex + if src.type == DoorType.StraightStairs: + bitmask += 0x40 + return [self.roomIndex, bitmask + 0x03] if self.type == DoorType.SpiralStairs: bitmask = int(self.layer) << 2 bitmask += 0x10 * int(self.zeroHzCam) @@ -1316,7 +1327,7 @@ class Door(object): return self def no_exit(self): - self.blocked = True + self.blocked = self.blocked_orig = True return self def no_entrance(self): diff --git a/DoorShuffle.py b/DoorShuffle.py index 91f5716f..b19e257a 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -8,17 +8,43 @@ from typing import DefaultDict, Dict, List from functools import reduce from BaseClasses import RegionType, Region, Door, DoorType, Direction, Sector, CrystalBarrier, DungeonInfo +from Doors import reset_portals from Dungeons import dungeon_regions, region_starts, standard_starts, split_region_starts from Dungeons import dungeon_bigs, dungeon_keys, dungeon_hints from Items import ItemFactory -from RoomData import DoorKind, PairedDoor +from RoomData import DoorKind, PairedDoor, reset_rooms from DungeonGenerator import ExplorationState, convert_regions, generate_dungeon, pre_validate, determine_required_paths, drop_entrances from DungeonGenerator import create_dungeon_builders, split_dungeon_builder, simple_dungeon_builder, default_dungeon_entrances -from DungeonGenerator import dungeon_portals, dungeon_drops +from DungeonGenerator import dungeon_portals, dungeon_drops, GenerationException from KeyDoorShuffle import analyze_dungeon, validate_vanilla_key_logic, build_key_layout, validate_key_layout def link_doors(world, player): + attempt, valid = 1, False + while not valid: + try: + link_doors_main(world, player) + valid = True + except GenerationException as e: + logging.getLogger('').debug(f'Irreconcilable generation. {str(e)} Starting a new attempt.') + attempt += 1 + if attempt > 10: + raise Exception('Could not create world in 10 attempts. Generation algorithms need more work', e) + for door in world.doors: + if door.player == player: + door.dest = None + door.entranceFlag = False + ent = door.entrance + if door.type != DoorType.Logical and ent.connected_region is not None: + ent.connected_region.entrances = [x for x in ent.connected_region.entrances if x != ent] + ent.connected_region = None + for portal in world.dungeon_portals[player]: + disconnect_portal(portal, world, player) + reset_portals(world, player) + reset_rooms(world, player) + + +def link_doors_main(world, player): # Drop-down connections & push blocks for exitName, regionName in logical_connections: @@ -32,20 +58,21 @@ def link_doors(world, player): connect_simple_door(world, exitName, regionName, player) for exitName, regionName in dungeon_warps: connect_simple_door(world, exitName, regionName, player) - for ent, ext in ladders: - connect_two_way(world, ent, ext, player) if world.intensity[player] < 2: for entrance, ext in open_edges: connect_two_way(world, entrance, ext, player) for entrance, ext in straight_staircases: connect_two_way(world, entrance, ext, player) + for entrance, ext in ladders: + connect_two_way(world, entrance, ext, player) if world.intensity[player] < 3 or world.doorShuffle == 'vanilla': mirror_route = world.get_entrance('Sanctuary Mirror Route', player) mr_door = mirror_route.door sanctuary = mirror_route.parent_region - sanctuary.exits.remove(mirror_route) + if mirror_route in sanctuary.exits: + sanctuary.exits.remove(mirror_route) world.remove_entrance(mirror_route, player) world.remove_door(mr_door, player) @@ -60,9 +87,12 @@ def link_doors(world, player): if world.mode[player] == 'standard': world.get_portal('Sanctuary', player).destination = True world.get_portal('Desert East', player).destination = True - world.get_portal('Skull 2 West', player).destination = True - world.get_portal('Turtle Rock Lazy Eyes', player).destination = True - world.get_portal('Turtle Rock Eye Bridge', player).destination = True + if world.mode[player] == 'inverted': + world.get_portal('Desert West', player).destination = True + if world.mode[player] == 'open': + world.get_portal('Skull 2 West', player).destination = True + world.get_portal('Turtle Rock Lazy Eyes', player).destination = True + world.get_portal('Turtle Rock Eye Bridge', player).destination = True else: analyze_portals(world, player) for portal in world.dungeon_portals[player]: @@ -77,6 +107,8 @@ def link_doors(world, player): connect_simple_door(world, exitName, regionName, player) for entrance, ext in spiral_staircases: connect_two_way(world, entrance, ext, player) + for entrance, ext in ladders: + connect_two_way(world, entrance, ext, player) for entrance, ext in default_door_connections: connect_two_way(world, entrance, ext, player) for ent, ext in default_one_way_connections: @@ -131,7 +163,7 @@ def create_door_spoiler(world, player): door_a = ext.door connect = ext.connected_region if door_a and door_a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, - DoorType.StraightStairs] and door_a not in done: + DoorType.StraightStairs, DoorType.Ladder] and door_a not in done: done.add(door_a) door_b = door_a.dest if door_b and not isinstance(door_b, Region): @@ -385,7 +417,10 @@ def choose_portals(world, player): possible_portals = outstanding_portals if not info.sole_entrance else [x for x in outstanding_portals if x != info.sole_entrance] choice, portal = assign_portal(candidates, possible_portals, world, player) if choice.deadEnd: - portal.deadEnd = True + if choice.passage: + portal.destination = True + else: + portal.deadEnd = True clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals) the_rest = info.total - len(portal_assignment[dungeon]) for i in range(0, the_rest): @@ -474,7 +509,6 @@ def connect_portal(portal, world, player): ent, ext, entrance_name = portal_map[portal.name] if world.mode[player] == 'inverted' and portal.name in ['Ganons Tower', 'Agahnims Tower']: ext = 'Inverted ' + ext - # ent = 'Inverted ' + ent portal_entrance = world.get_entrance(portal.door.entrance.name, player) # ensures I get the right one for copying target_exit = world.get_entrance(ext, player) portal_entrance.connected_region = target_exit.parent_region @@ -485,23 +519,21 @@ def connect_portal(portal, world, player): chosen_door = world.get_door(portal_entrance.name, player) chosen_door.blocked = False connect_door_only(world, chosen_door, portal_region, player) + portal_entrance.parent_region.entrances.append(edit_entrance) -# todo: remove this? -def connect_portal_copy(portal, world, player): +def disconnect_portal(portal, world, player): ent, ext, entrance_name = portal_map[portal.name] - if world.mode[player] == 'inverted' and portal.name in ['Ganons Tower', 'Agahnims Tower']: - ext = 'Inverted ' + ext - portal_entrance = world.get_entrance(portal.door.entrance.name, player) # ensures I get the right one for copying - target_exit = world.get_entrance(ext, player) - portal_entrance.connected_region = target_exit.parent_region - portal_region = world.get_region(portal.name + ' Portal', player) - portal_region.entrances.append(portal_entrance) + portal_entrance = world.get_entrance(portal.door.entrance.name, player) + # portal_region = world.get_region(portal.name + ' Portal', player) edit_entrance = world.get_entrance(entrance_name, player) - edit_entrance.connected_region = portal_entrance.parent_region chosen_door = world.get_door(portal_entrance.name, player) - chosen_door.blocked = False - connect_door_only(world, chosen_door, portal_region, player) + + # reverse work + if edit_entrance in portal_entrance.parent_region.entrances: + portal_entrance.parent_region.entrances.remove(edit_entrance) + chosen_door.blocked = chosen_door.blocked_orig + chosen_door.entranceFlag = False def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False): @@ -638,7 +670,7 @@ def within_dungeon(world, player): dungeon_builders[key].entrance_list = list(entrances_map[key]) recombinant_builders = {} entrances, splits = create_dungeon_entrances(world, player) - builder_info = entrances, splits, world, player + builder_info = entrances, splits, connections_tuple, world, player handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, builder_info) main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player) @@ -662,12 +694,12 @@ def within_dungeon(world, player): def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, builder_info): - dungeon_entrances, split_dungeon_entrances, world, player = builder_info + dungeon_entrances, split_dungeon_entrances, c_tuple, world, player = builder_info if dungeon_entrances is None: dungeon_entrances = default_dungeon_entrances if split_dungeon_entrances is None: split_dungeon_entrances = split_region_starts - builder_info = dungeon_entrances, split_dungeon_entrances, world, player + builder_info = dungeon_entrances, split_dungeon_entrances, c_tuple, world, player for name, split_list in split_dungeon_entrances.items(): builder = dungeon_builders.pop(name) @@ -705,10 +737,11 @@ def main_dungeon_generation(dungeon_builders, recombinant_builders, connections_ continue origin_list = list(builder.entrance_list) find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, name) + split_dungeon = treat_split_as_whole_dungeon(split_dungeon, name, origin_list, world, player) if len(origin_list) <= 0 or not pre_validate(builder, origin_list, split_dungeon, world, player): if last_key == builder.name or loops > 1000: origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name if len(origin_list) > 0 else 'no origin' - raise Exception('Infinite loop detected for "%s" located at %s' % (builder.name, origin_name)) + raise GenerationException(f'Infinite loop detected for "{builder.name}" located at {origin_name}') sector_queue.append(builder) last_key = builder.name loops += 1 @@ -852,6 +885,22 @@ def aga_tower_enabled(enabled): return False +def treat_split_as_whole_dungeon(split_dungeon, name, origin_list, world, player): + # what about ER dungeons? - find an example? (bad key doors 0 keys not valid) + if split_dungeon and name in multiple_portal_map: + possible_entrances = [] + for portal_name in multiple_portal_map[name]: + portal = world.get_portal(portal_name, player) + portal_entrance = world.get_entrance(portal_map[portal_name][0], player) + if not portal.destination and portal_entrance.parent_region.name not in world.inaccessible_regions[player]: + possible_entrances.append(portal) + if len(possible_entrances) == 1: + single_portal = possible_entrances[0] + if single_portal.door.entrance.parent_region.name in origin_list and len(origin_list) == 1: + return False + return split_dungeon + + # goals: # 1. have enough chests to be interesting (2 more than dungeon items) # 2. have a balanced amount of regions added (check) @@ -886,7 +935,7 @@ def cross_dungeon(world, player): key_name = dungeon_keys[builder.name] if loc.name != 'Hyrule Castle - Big Key Drop' else dungeon_bigs[builder.name] loc.forced_item = loc.item = ItemFactory(key_name, player) recombinant_builders = {} - builder_info = entrances, splits, world, player + builder_info = entrances, splits, connections_tuple, world, player handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, builder_info) main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player) @@ -1277,11 +1326,10 @@ def combine_layouts(recombinant_builders, dungeon_builders, entrances_map): if recombine.master_sector is None: recombine.master_sector = builder.master_sector recombine.master_sector.name = recombine.name - recombine.pre_open_stonewall = builder.pre_open_stonewall + recombine.pre_open_stonewalls = builder.pre_open_stonewalls else: recombine.master_sector.regions.extend(builder.master_sector.regions) - if builder.pre_open_stonewall: - recombine.pre_open_stonewall = builder.pre_open_stonewall + recombine.pre_open_stonewalls.update(builder.pre_open_stonewalls) recombine.layout_starts = list(entrances_map[recombine.name]) dungeon_builders[recombine.name] = recombine @@ -1609,6 +1657,7 @@ def change_door_to_small_key(d, world, player): def smooth_door_pairs(world, player): all_doors = [x for x in world.doors if x.player == player] skip = set() + bd_candidates, dashable_counts, bombable_counts = defaultdict(list), defaultdict(int), defaultdict(int) for door in all_doors: if door.type in [DoorType.Normal, DoorType.Interior] and door not in skip and not door.entranceFlag: partner = door.dest @@ -1636,19 +1685,18 @@ def smooth_door_pairs(world, player): remove_pair(door, world, player) elif type_a in [DoorKind.Bombable, DoorKind.Dashable] or type_b in [DoorKind.Bombable, DoorKind.Dashable]: if valid_pair: - if type_a == type_b: - add_pair(door, partner, world, player) - spoiler_type = 'Bomb Door' if type_a == DoorKind.Bombable else 'Dash Door' - world.spoiler.set_door_type(door.name + ' <-> ' + partner.name, spoiler_type, player) - else: + new_type = type_a + if type_a != type_b: new_type = DoorKind.Dashable if type_a == DoorKind.Dashable or type_b == DoorKind.Dashable else DoorKind.Bombable if type_a != new_type: room_a.change(door.doorListPos, new_type) if type_b != new_type: room_b.change(partner.doorListPos, new_type) - add_pair(door, partner, world, player) - spoiler_type = 'Bomb Door' if new_type == DoorKind.Bombable else 'Dash Door' - world.spoiler.set_door_type(door.name + ' <-> ' + partner.name, spoiler_type, player) + add_pair(door, partner, world, player) + spoiler_type = 'Bomb Door' if new_type == DoorKind.Bombable else 'Dash Door' + world.spoiler.set_door_type(door.name + ' <-> ' + partner.name, spoiler_type, player) + counter = bombable_counts if new_type == DoorKind.Bombable else dashable_counts + counter[door.entrance.parent_region.dungeon] += 1 else: if type_a in [DoorKind.Bombable, DoorKind.Dashable]: room_a.change(door.doorListPos, DoorKind.Normal) @@ -1656,8 +1704,9 @@ def smooth_door_pairs(world, player): elif type_b in [DoorKind.Bombable, DoorKind.Dashable]: room_b.change(partner.doorListPos, DoorKind.Normal) remove_pair(partner, world, player) - elif world.experimental[player] and valid_pair and type_a != DoorKind.SmallKey and type_b != DoorKind.SmallKey: - random_door_type(door, partner, world, player, type_a, type_b, room_a, room_b) + elif valid_pair and type_a != DoorKind.SmallKey and type_b != DoorKind.SmallKey: + bd_candidates[door.entrance.parent_region.dungeon].append(door) + shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, world, player) world.paired_doors[player] = [x for x in world.paired_doors[player] if x.pair or x.original] @@ -1694,17 +1743,59 @@ def stateful_door(door, kind): return False -def random_door_type(door, partner, world, player, type_a, type_b, room_a, room_b): - r_kind = random.choices([DoorKind.Normal, DoorKind.Bombable, DoorKind.Dashable], [15, 4, 6], k=1)[0] - if r_kind != DoorKind.Normal: - if door.type == DoorType.Normal: - add_pair(door, partner, world, player) - if type_a != r_kind: - room_a.change(door.doorListPos, r_kind) - if type_b != r_kind: - room_b.change(partner.doorListPos, r_kind) - spoiler_type = 'Bomb Door' if r_kind == DoorKind.Bombable else 'Dash Door' - world.spoiler.set_door_type(door.name + ' <-> ' + partner.name, spoiler_type, player) +def shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, world, player): + if world.doorShuffle[player] == 'basic': + for dungeon, candidates in bd_candidates.items(): + diff = bomb_dash_counts[dungeon.name][1] - dashable_counts[dungeon] + if diff > 0: + for chosen in random.sample(candidates, min(diff, len(candidates))): + change_pair_type(chosen, DoorKind.Dashable, world, player) + candidates.remove(chosen) + diff = bomb_dash_counts[dungeon.name][0] - bombable_counts[dungeon] + if diff > 0: + for chosen in random.sample(candidates, min(diff, len(candidates))): + change_pair_type(chosen, DoorKind.Bombable, world, player) + candidates.remove(chosen) + for excluded in candidates: + remove_pair_type_if_present(excluded, world, player) + elif world.doorShuffle[player] == 'crossed': + all_candidates = sum(bd_candidates.values(), []) + all_bomb_counts = sum(bombable_counts.values()) + all_dash_counts = sum(dashable_counts.values()) + if all_dash_counts < 8: + for chosen in random.sample(all_candidates, min(8 - all_dash_counts, len(all_candidates))): + change_pair_type(chosen, DoorKind.Dashable, world, player) + all_candidates.remove(chosen) + if all_bomb_counts < 12: + for chosen in random.sample(all_candidates, min(12 - all_bomb_counts, len(all_candidates))): + change_pair_type(chosen, DoorKind.Bombable, world, player) + all_candidates.remove(chosen) + for excluded in all_candidates: + remove_pair_type_if_present(excluded, world, player) + + +def change_pair_type(door, new_type, world, player): + room_a = world.get_room(door.roomIndex, player) + room_a.change(door.doorListPos, new_type) + if door.type != DoorType.Interior: + room_b = world.get_room(door.dest.roomIndex, player) + room_b.change(door.dest.doorListPos, new_type) + add_pair(door, door.dest, world, player) + spoiler_type = 'Bomb Door' if new_type == DoorKind.Bombable else 'Dash Door' + world.spoiler.set_door_type(door.name + ' <-> ' + door.dest.name, spoiler_type, player) + + +def remove_pair_type_if_present(door, world, player): + room_a = world.get_room(door.roomIndex, player) + if room_a.kind(door) in [DoorKind.Bombable, DoorKind.Dashable]: + room_a.change(door.doorListPos, DoorKind.Normal) + if door.type != DoorType.Interior: + remove_pair(door, world, player) + if door.type != DoorType.Interior: + room_b = world.get_room(door.dest.roomIndex, player) + if room_b.kind(door.dest) in [DoorKind.Bombable, DoorKind.Dashable]: + room_b.change(door.dest.doorListPos, DoorKind.Normal) + remove_pair(door.dest, world, player) def find_inaccessible_regions(world, player): @@ -1727,8 +1818,9 @@ def find_inaccessible_regions(world, player): queue.append(parent) for ext in next_region.exits: connect = ext.connected_region - if connect and connect.type is not RegionType.Dungeon and connect not in queue and connect not in visited_regions: - queue.append(connect) + if connect and connect not in queue and connect not in visited_regions: + if connect.type is not RegionType.Dungeon or connect.name.endswith(' Portal'): + queue.append(connect) world.inaccessible_regions[player].extend([r.name for r in all_regions.difference(visited_regions) if valid_inaccessible_region(r)]) logger = logging.getLogger('') logger.debug('Inaccessible Regions:') @@ -1816,12 +1908,12 @@ def check_required_paths(paths, world, player): if dungeon_name in world.dungeon_layouts[player].keys(): builder = world.dungeon_layouts[player][dungeon_name] if len(paths[dungeon_name]) > 0: - states_to_explore = {} + states_to_explore = defaultdict(list) for path in paths[dungeon_name]: if type(path) is tuple: states_to_explore[tuple([path[0]])] = path[1] else: - states_to_explore[tuple(builder.path_entrances)] = path + states_to_explore[tuple(builder.path_entrances)].append(path) cached_initial_state = None for start_regs, dest_regs in states_to_explore.items(): if type(dest_regs) is not list: @@ -1890,13 +1982,14 @@ def check_if_regions_visited(state, check_paths): if state.visited_at_all(region_target): valid = True break - else: + elif not breaking_region: breaking_region = region_target return valid, breaking_region def check_for_pinball_fix(state, bad_region, world, player): pinball_region = world.get_region('Skull Pinball', player) + # todo: lobby shuffle if bad_region.name == 'Skull 2 West Lobby' and state.visited_at_all(pinball_region): # revisit this for entrance shuffle door = world.get_door('Skull Pinball WS', player) room = world.get_room(door.roomIndex, player) @@ -1919,7 +2012,7 @@ class DROptions(Flag): Debug = 0x08 Rails = 0x10 # If on, draws rails OriginalPalettes = 0x20 - Reserved = 0x40 # Reserved for PoD sliding wall? + Open_PoD_Wall = 0x40 # If on, pre opens the PoD wall, no bow required Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required @@ -1952,6 +2045,13 @@ logical_connections = [ ('PoD Basement Ledge Drop Down', 'PoD Stalfos Basement'), ('PoD Falling Bridge Path N', 'PoD Falling Bridge Ledge'), ('PoD Falling Bridge Path S', 'PoD Falling Bridge'), + ('PoD Bow Statue Crystal Path', 'PoD Bow Statue Moving Wall'), + ('PoD Bow Statue Moving Wall Path', 'PoD Bow Statue'), + ('PoD Bow Statue Moving Wall Cane Path', 'PoD Bow Statue'), + ('PoD Dark Pegs Hammer Path', 'PoD Dark Pegs Ladder'), + ('PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs'), + ('PoD Dark Pegs Ladder Cane Path', 'PoD Dark Pegs Switch'), + ('PoD Dark Pegs Switch Path', 'PoD Dark Pegs Ladder'), ('Swamp Lobby Moat', 'Swamp Entrance'), ('Swamp Entrance Moat', 'Swamp Lobby'), ('Swamp Trench 1 Approach Dry', 'Swamp Trench 1 Nexus'), @@ -2780,6 +2880,14 @@ portal_map = { 'Ganons Tower': ('Ganons Tower', 'Ganons Tower Exit', 'Enter Ganons Tower'), } + +multiple_portal_map = { + 'Hyrule Castle': ['Sanctuary', 'Hyrule Castle West', 'Hyrule Castle South', 'Hyrule Castle East'], + 'Desert Palace': ['Desert West', 'Desert South', 'Desert East', 'Desert Back'], + 'Skull Woods': ['Skull 1', 'Skull 2 West', 'Skull 2 East', 'Skull 3'], + 'Turtle Rock': ['Turtle Rock Lazy Eyes', 'Turtle Rock Eye Bridge', 'Turtle Rock Chest', 'Turtle Rock Main'], +} + split_portals = { 'Desert Palace': ['Back', 'Main'], 'Skull Woods': ['1', '2', '3'] @@ -2800,4 +2908,20 @@ split_portal_defaults = { } } +bomb_dash_counts = { + 'Hyrule Castle': (0, 2), + 'Eastern Palace': (0, 0), + 'Desert Palace': (0, 0), + 'Agahnims Tower': (0, 0), + 'Swamp Palace': (2, 0), + 'Palace of Darkness': (3, 2), + 'Misery Mire': (2, 0), + 'Skull Woods': (2, 0), + 'Ice Palace': (0, 0), + 'Tower of Hera': (0, 0), + 'Thieves Town': (1, 1), + 'Turtle Rock': (0, 2), # 2 bombs kind of for entrances + 'Ganons Tower': (2, 1) +} + diff --git a/Doors.py b/Doors.py index 460bf0d9..3bc41766 100644 --- a/Doors.py +++ b/Doors.py @@ -395,8 +395,15 @@ def create_doors(world, player): create_door(player, 'PoD Mimics 2 SW', Nrml).dir(So, 0x1b, Left, High).pos(1).kill().portal(Z, 0x00), create_door(player, 'PoD Mimics 2 NW', Intr).dir(No, 0x1b, Left, High).pos(0), create_door(player, 'PoD Bow Statue SW', Intr).dir(So, 0x1b, Left, High).pos(0), - create_door(player, 'PoD Bow Statue Down Ladder', Lddr).no_entrance(), - create_door(player, 'PoD Dark Pegs Up Ladder', Lddr), + create_door(player, 'PoD Bow Statue Crystal Path', Lgcl), + create_door(player, 'PoD Bow Statue Moving Wall Path', Lgcl), + create_door(player, 'PoD Bow Statue Moving Wall Cane Path', Lgcl), + create_door(player, 'PoD Bow Statue Down Ladder', Lddr).dir(So, 0x1b, 1, High).no_entrance(), + create_door(player, 'PoD Dark Pegs Up Ladder', Lddr).dir(No, 0x0b, 0, High), + create_door(player, 'PoD Dark Pegs Hammer Path', Lgcl), + create_door(player, 'PoD Dark Pegs Ladder Hammer Path', Lgcl), + create_door(player, 'PoD Dark Pegs Ladder Cane Path', Lgcl), + create_door(player, 'PoD Dark Pegs Switch Path', Lgcl), create_door(player, 'PoD Dark Pegs WN', Intr).dir(We, 0x0b, Mid, High).small_key().pos(2), create_door(player, 'PoD Lonely Turtle SW', Intr).dir(So, 0x0b, Mid, High).pos(0), create_door(player, 'PoD Lonely Turtle EN', Intr).dir(Ea, 0x0b, Mid, High).small_key().pos(2), @@ -663,7 +670,7 @@ def create_doors(world, player): create_door(player, 'Ice Pengator Switch ES', Intr).dir(Ea, 0x1f, Bot, High).pos(1), create_door(player, 'Ice Dead End WS', Intr).dir(We, 0x1f, Bot, High).pos(1), create_door(player, 'Ice Big Key Push Block', Lgcl), - create_door(player, 'Ice Big Key Down Ladder', Lddr), + create_door(player, 'Ice Big Key Down Ladder', Lddr).dir(So, 0x1f, 3, High), create_door(player, 'Ice Stalfos Hint SE', Intr).dir(So, 0x3e, Right, High).pos(0), create_door(player, 'Ice Conveyor NE', Intr).dir(No, 0x3e, Right, High).no_exit().pos(0), create_door(player, 'Ice Conveyor SW', Nrml).dir(So, 0x3e, Left, High).small_key().pos(1).portal(Z, 0x20), @@ -679,7 +686,7 @@ def create_doors(world, player): create_door(player, 'Ice Spike Cross ES', Nrml).dir(Ea, 0x5e, Bot, High).small_key().pos(0), create_door(player, 'Ice Spike Cross WS', Intr).dir(We, 0x5e, Bot, High).pos(3), create_door(player, 'Ice Firebar ES', Intr).dir(Ea, 0x5e, Bot, High).pos(3), - create_door(player, 'Ice Firebar Down Ladder', Lddr), + create_door(player, 'Ice Firebar Down Ladder', Lddr).dir(So, 0x5e, 5, High), create_door(player, 'Ice Spike Cross NE', Intr).dir(No, 0x5e, Right, High).pos(1), create_door(player, 'Ice Falling Square SE', Intr).dir(So, 0x5e, Right, High).no_exit().pos(1), create_door(player, 'Ice Falling Square Hole', Hole), @@ -689,8 +696,8 @@ def create_doors(world, player): create_door(player, 'Ice Hammer Block Down Stairs', Sprl).dir(Dn, 0x3f, 0, HTH).ss(Z, 0x11, 0xb8, True, True).kill(), create_door(player, 'Ice Hammer Block ES', Intr).dir(Ea, 0x3f, Bot, High).pos(0), create_door(player, 'Ice Tongue Pull WS', Intr).dir(We, 0x3f, Bot, High).pos(0), - create_door(player, 'Ice Tongue Pull Up Ladder', Lddr), - create_door(player, 'Ice Freezors Up Ladder', Lddr), + create_door(player, 'Ice Tongue Pull Up Ladder', Lddr).dir(No, 0x3f, 2, High), + create_door(player, 'Ice Freezors Up Ladder', Lddr).dir(No, 0x7e, 4, High), create_door(player, 'Ice Freezors Hole', Hole), create_door(player, 'Ice Freezors Bomb Hole', Hole), # combine these two? -- they have to lead to the same spot create_door(player, 'Ice Freezors Ledge Hole', Hole), @@ -1078,8 +1085,8 @@ def create_doors(world, player): create_door(player, 'GT Torch Cross WN', Nrml).dir(We, 0x96, Top, High).pos(1), create_door(player, 'GT Torch Cross ES', Intr).dir(Ea, 0x96, Bot, High).pos(0), create_door(player, 'GT Staredown WS', Intr).dir(We, 0x96, Bot, High).pos(0), - create_door(player, 'GT Staredown Up Ladder', Lddr), - create_door(player, 'GT Falling Torches Down Ladder', Lddr), + create_door(player, 'GT Staredown Up Ladder', Lddr).dir(No, 0x96, 6, High), + create_door(player, 'GT Falling Torches Down Ladder', Lddr).dir(So, 0x3d, 7, High), create_door(player, 'GT Falling Torches NE', Intr).dir(No, 0x3d, Right, High).pos(0), create_door(player, 'GT Mini Helmasaur Room SE', Intr).dir(So, 0x3d, Right, High).pos(0), create_door(player, 'GT Falling Torches Hole', Hole), @@ -1156,9 +1163,11 @@ def create_doors(world, player): world.get_door('PoD Map Balcony WS', player).c_switch() world.get_door('PoD Map Balcony South Stairs', player).c_switch() world.get_door('PoD Bow Statue SW', player).c_switch() - world.get_door('PoD Bow Statue Down Ladder', player).c_switch() - world.get_door('PoD Dark Pegs Up Ladder', player).c_switch() + world.get_door('PoD Bow Statue Moving Wall Path', player).barrier(CrystalBarrier.Orange) + world.get_door('PoD Bow Statue Crystal Path', player).c_switch() world.get_door('PoD Dark Pegs WN', player).c_switch() + world.get_door('PoD Dark Pegs Switch Path', player).c_switch() + world.get_door('PoD Dark Pegs Hammer Path', player).c_switch() world.get_door('Swamp Crystal Switch EN', player).c_switch() world.get_door('Swamp Crystal Switch SE', player).c_switch() @@ -1271,36 +1280,11 @@ def create_doors(world, player): assign_entrances(world, player) - dungeon_portals = [ - create_portal(player, 'Sanctuary', world.get_door('Sanctuary S', player), 0x02, 0x02), - create_portal(player, 'Hyrule Castle West', world.get_door('Hyrule Castle West Lobby S', player), 0x03, 0x04), - create_portal(player, 'Hyrule Castle South', world.get_door('Hyrule Castle Lobby S', player), 0x04, 0x06), - create_portal(player, 'Hyrule Castle East', world.get_door('Hyrule Castle East Lobby S', player), 0x05, 0x08), - create_portal(player, 'Eastern', world.get_door('Eastern Lobby S', player), 0x08, 0x12, 0), - create_portal(player, 'Desert South', world.get_door('Desert Main Lobby S', player), 0x09, 0x14), - create_portal(player, 'Desert East', world.get_door('Desert East Lobby S', player), 0x0a, 0x16), - create_portal(player, 'Desert West', world.get_door('Desert West S', player), 0x0b, 0x18), - create_portal(player, 'Desert Back', world.get_door('Desert Back Lobby S', player), 0x0c, 0x1a, 1), - create_portal(player, 'Turtle Rock Lazy Eyes', world.get_door('TR Lazy Eyes SE', player), 0x15, 0x2c), - create_portal(player, 'Turtle Rock Eye Bridge', world.get_door('TR Eye Bridge SW', player), 0x18, 0x32), - create_portal(player, 'Turtle Rock Chest', world.get_door('TR Big Chest Entrance SE', player), 0x19, 0x34), - create_portal(player, 'Agahnims Tower', world.get_door('Tower Lobby S', player), 0x24, 0x4a), - create_portal(player, 'Swamp', world.get_door('Swamp Lobby S', player), 0x25, 0x4c, 4), - create_portal(player, 'Palace of Darkness', world.get_door('PoD Lobby S', player), 0x26, 0x4e, 5), - create_portal(player, 'Mire', world.get_door('Mire Lobby S', player), 0x27, 0x50, 7), - create_portal(player, 'Skull 2 West', world.get_door('Skull 2 West Lobby S', player), 0x28, 0x52), - create_portal(player, 'Skull 2 East', world.get_door('Skull 2 East Lobby SW', player), 0x29, 0x54), - create_portal(player, 'Skull 1', world.get_door('Skull 1 Lobby S', player), 0x2a, 0x56), - create_portal(player, 'Skull 3', world.get_door('Skull 3 Lobby SW', player), 0x2b, 0x58, 6), - create_portal(player, 'Ice', world.get_door('Ice Lobby SE', player), 0x2d, 0x5c, 8), - create_portal(player, 'Hera', world.get_door('Hera Lobby S', player), 0x33, 0x5a, 2), - create_portal(player, 'Thieves Town', world.get_door('Thieves Lobby S', player), 0x34, 0x6a, 10), - create_portal(player, 'Turtle Rock Main', world.get_door('TR Main Lobby SE', player), 0x35, 0x68, 9), - create_portal(player, 'Ganons Tower', world.get_door('GT Lobby S', player), 0x37, 0x70), - ] - world.dungeon_portals[player] += dungeon_portals + create_portals(world, player) + # static portal flags world.get_door('Sanctuary S', player).dead_end(allowPassage=True) + world.get_door('Eastern Hint Tile Blocked Path SE', player).passage = False world.get_door('TR Big Chest Entrance SE', player).passage = False world.get_door('Sewers Secret Room Key Door S', player).dungeonLink = 'Hyrule Castle' world.get_door('Desert Cannonball S', player).dead_end() @@ -1336,6 +1320,42 @@ def create_doors(world, player): world.get_door('Ice Conveyor SW', player).dungeonLink = 'linkIceFalls2' +def create_portals(world, player): + dungeon_portals = [ + create_portal(player, 'Sanctuary', world.get_door('Sanctuary S', player), 0x02, 0x02), + create_portal(player, 'Hyrule Castle West', world.get_door('Hyrule Castle West Lobby S', player), 0x03, 0x04), + create_portal(player, 'Hyrule Castle South', world.get_door('Hyrule Castle Lobby S', player), 0x04, 0x06), + create_portal(player, 'Hyrule Castle East', world.get_door('Hyrule Castle East Lobby S', player), 0x05, 0x08), + create_portal(player, 'Eastern', world.get_door('Eastern Lobby S', player), 0x08, 0x12, 0), + create_portal(player, 'Desert South', world.get_door('Desert Main Lobby S', player), 0x09, 0x14), + create_portal(player, 'Desert East', world.get_door('Desert East Lobby S', player), 0x0a, 0x16), + create_portal(player, 'Desert West', world.get_door('Desert West S', player), 0x0b, 0x18), + create_portal(player, 'Desert Back', world.get_door('Desert Back Lobby S', player), 0x0c, 0x1a, 1), + create_portal(player, 'Turtle Rock Lazy Eyes', world.get_door('TR Lazy Eyes SE', player), 0x15, 0x2c), + create_portal(player, 'Turtle Rock Eye Bridge', world.get_door('TR Eye Bridge SW', player), 0x18, 0x32), + create_portal(player, 'Turtle Rock Chest', world.get_door('TR Big Chest Entrance SE', player), 0x19, 0x34), + create_portal(player, 'Agahnims Tower', world.get_door('Tower Lobby S', player), 0x24, 0x4a), + create_portal(player, 'Swamp', world.get_door('Swamp Lobby S', player), 0x25, 0x4c, 4), + create_portal(player, 'Palace of Darkness', world.get_door('PoD Lobby S', player), 0x26, 0x4e, 5), + create_portal(player, 'Mire', world.get_door('Mire Lobby S', player), 0x27, 0x50, 7), + create_portal(player, 'Skull 2 West', world.get_door('Skull 2 West Lobby S', player), 0x28, 0x52), + create_portal(player, 'Skull 2 East', world.get_door('Skull 2 East Lobby SW', player), 0x29, 0x54), + create_portal(player, 'Skull 1', world.get_door('Skull 1 Lobby S', player), 0x2a, 0x56), + create_portal(player, 'Skull 3', world.get_door('Skull 3 Lobby SW', player), 0x2b, 0x58, 6), + create_portal(player, 'Ice', world.get_door('Ice Lobby SE', player), 0x2d, 0x5c, 8), + create_portal(player, 'Hera', world.get_door('Hera Lobby S', player), 0x33, 0x5a, 2), + create_portal(player, 'Thieves Town', world.get_door('Thieves Lobby S', player), 0x34, 0x6a, 10), + create_portal(player, 'Turtle Rock Main', world.get_door('TR Main Lobby SE', player), 0x35, 0x68, 9), + create_portal(player, 'Ganons Tower', world.get_door('GT Lobby S', player), 0x37, 0x70), + ] + world.dungeon_portals[player] += dungeon_portals + + +def reset_portals(world, player): + world.dungeon_portals[player].clear() + world._portal_cache.clear() + create_portals(world, player) + def create_paired_doors(world, player): world.paired_doors[player] = [ PairedDoor('Sewers Secret Room Key Door S', 'Sewers Key Rat Key Door N', True), diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 1ce3c637..e320bbaf 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -55,19 +55,21 @@ def pre_validate(builder, entrance_region_names, split_dungeon, world, player): def generate_dungeon(builder, entrance_region_names, split_dungeon, world, player): - stonewall = check_for_stonewall(builder) + stonewalls = check_for_stonewalls(builder) sector = generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player) - if stonewall and not stonewall_valid(stonewall): - builder.pre_open_stonewall = stonewall + for stonewall in stonewalls: + if not stonewall_valid(stonewall): + builder.pre_open_stonewalls.add(stonewall) return sector -def check_for_stonewall(builder): +def check_for_stonewalls(builder): + stonewalls = set() for sector in builder.sectors: for door in sector.outstanding_doors: if door.stonewall: - return door - return None + stonewalls.add(door) + return stonewalls def generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player): @@ -226,7 +228,7 @@ def gen_dungeon_info(name, available_sectors, entrance_regions, all_regions, pro o_state_cache = {} for sector in available_sectors: for door in sector.outstanding_doors: - if not door.stonewall and door not in proposed_map.keys(): + if door not in proposed_map.keys(): hanger_set.add(door) bk_flag = group_flags[door_map[door]] parent = door.entrance.parent_region @@ -418,8 +420,7 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a true_origin_hooks = [x for x in dungeon['Origin'].hooks.keys() if not x.bigKey or possible_bks > 0 or not bk_needed] if len(true_origin_hooks) == 0 and len(proposed_map.keys()) < len(doors_to_connect): return False - if len(true_origin_hooks) == 0 and bk_needed and possible_bks == 0 and len(proposed_map.keys()) == len( - doors_to_connect): + if len(true_origin_hooks) == 0 and bk_needed and possible_bks == 0 and len(proposed_map.keys()) == len(doors_to_connect): return False for key in hangers.keys(): if len(hooks[key]) > 0 and len(hangers[key]) == 0: @@ -619,7 +620,7 @@ def stonewall_valid(stonewall): return False # you can get stuck from an entrance else: door = entrance.door - if door is not None and door != stonewall and not door.blocked and parent not in visited: + if (door is None or (door != stonewall and not door.blocked)) and parent not in visited: visited.add(parent) queue.append(parent) # we didn't find anything bad @@ -694,17 +695,17 @@ hang_dir_map = { def hanger_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: return hang_dir_map[door.direction] return None def connect_doors(a, b): # Return on unsupported types. - if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Ladder, DoorType.Interior, DoorType.Logical]: + if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Interior, DoorType.Logical]: return # Connect supported types - if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs]: + if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: if a.blocked: connect_one_way(b.entrance, a.entrance) elif b.blocked: @@ -1171,7 +1172,7 @@ class DungeonBuilder(object): self.path_entrances = None # used for pathing/key doors, I think self.split_flag = False - self.pre_open_stonewall = None # used by stonewall system + self.pre_open_stonewalls = set() # used by stonewall system self.candidates = None self.key_doors_num = None @@ -1225,15 +1226,15 @@ def simple_dungeon_builder(name, sector_list): def create_dungeon_builders(all_sectors, connections_tuple, world, player, dungeon_entrances=None, split_dungeon_entrances=None): logger = logging.getLogger('') + logger.info('Shuffling Dungeon Sectors') if dungeon_entrances is None: dungeon_entrances = default_dungeon_entrances if split_dungeon_entrances is None: split_dungeon_entrances = split_region_starts define_sector_features(all_sectors) - finished, dungeon_map = False, {} + finished, dungeon_map, attempts = False, {}, 0 while not finished: - logger.info('Shuffling Dungeon Sectors') candidate_sectors = dict.fromkeys(all_sectors) global_pole = GlobalPolarity(candidate_sectors) @@ -1248,6 +1249,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, for r_name in ['Hyrule Dungeon Cellblock', 'Sanctuary']: # need to deliver zelda assign_sector(find_sector(r_name, candidate_sectors), current_dungeon, candidate_sectors, global_pole) + standard_stair_check(dungeon_map, current_dungeon, candidate_sectors, global_pole) entrances_map, potentials, connections = connections_tuple accessible_sectors, reverse_d_map = set(), {} for key in dungeon_entrances.keys(): @@ -1271,7 +1273,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, connections, dungeon_entrances, split_dungeon_entrances) for name, builder in dungeon_map.items(): - calc_allowance_and_dead_ends(builder, connections_tuple, world.dungeon_portals[player]) + calc_allowance_and_dead_ends(builder, connections_tuple, world, player) if world.mode[player] == 'open' and world.shuffle[player] not in ['crossed', 'insanity']: sanc = find_sector('Sanctuary', candidate_sectors) @@ -1318,17 +1320,33 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, # restart raise NeutralizingException('Either free location/crystal assignment is already globally invalid') logger.info(world.fish.translate("cli", "cli", "balance.doors")) - builder_info = dungeon_entrances, split_dungeon_entrances, world, player + builder_info = dungeon_entrances, split_dungeon_entrances, connections_tuple, world, player assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, builder_info) # the rest assign_the_rest(dungeon_map, neutral_sectors, global_pole, builder_info) dungeon_map.update(complete_dungeons) finished = True - except NeutralizingException: - pass + except (NeutralizingException, GenerationException) as e: + attempts += 1 + logger.debug(f'Attempt {attempts} failed with {str(e)}') + if attempts >= 10: + raise Exception('Could not find a valid seed quickly, something is likely horribly wrong.', e) return dungeon_map +def standard_stair_check(dungeon_map, dungeon, candidate_sectors, global_pole): + # this is because there must be at least one non-dead stairway in hc to get out + # this check may not be necessary + filtered_sectors = [x for x in candidate_sectors if any(y for y in x.outstanding_doors if not y.dead and y.type == DoorType.SpiralStairs)] + valid = False + while not valid: + chosen_sector = random.choice(filtered_sectors) + filtered_sectors.remove(chosen_sector) + valid = global_pole.is_valid_choice(dungeon_map, dungeon, [chosen_sector]) + if valid: + assign_sector(chosen_sector, dungeon, candidate_sectors, global_pole) + + def identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, connections, dungeon_entrances, split_dungeon_entrances): accessible_overworld, found_connections, explored = set(), set(), False @@ -1376,35 +1394,44 @@ def identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, break -def calc_allowance_and_dead_ends(builder, connections_tuple, portals): +# todo: split version that adds allowance for potential entrances +def calc_allowance_and_dead_ends(builder, connections_tuple, world, player): + portals = world.dungeon_portals[player] entrances_map, potentials, connections = connections_tuple - needed_connections = [x for x in builder.all_entrances if x not in entrances_map[builder.name]] + name = builder.name if not builder.split_flag else builder.name.rsplit(' ', 1)[0] + needed_connections = [x for x in builder.all_entrances if x not in entrances_map[name]] starting_allowance = 0 used_sectors = set() destination_entrances = [x.door.entrance.parent_region.name for x in portals if x.destination] - for entrance in entrances_map[builder.name]: + dead_ends = [x.door.entrance.parent_region.name for x in portals if x.deadEnd] + for entrance in entrances_map[name]: sector = find_sector(entrance, builder.sectors) - outflow_target = 0 if entrance not in drop_entrances_allowance else 1 - if sector not in used_sectors and sector.adj_outflow() > outflow_target: - if entrance not in destination_entrances: - starting_allowance += 1 - else: - builder.branches -= 1 - used_sectors.add(sector) - elif sector not in used_sectors: - if entrance in destination_entrances and sector.branches() > 0: - builder.branches -= 1 - if entrance not in drop_entrances_allowance: - needed_connections.append(entrance) + if sector: + outflow_target = 0 if entrance not in drop_entrances_allowance else 1 + if sector not in used_sectors and (sector.adj_outflow() > outflow_target or entrance in dead_ends): + if entrance not in destination_entrances: + starting_allowance += 1 + else: + builder.branches -= 1 + used_sectors.add(sector) + elif sector not in used_sectors: + if entrance in destination_entrances and sector.branches() > 0: + builder.branches -= 1 + if entrance not in drop_entrances_allowance: + needed_connections.append(entrance) builder.allowance = starting_allowance for entrance in needed_connections: sector = find_sector(entrance, builder.sectors) - if sector not in used_sectors: # ignore things on same sector + if sector and sector not in used_sectors: # ignore things on same sector is_destination = entrance in destination_entrances connect_able = False if entrance in connections.keys(): enabling_region = connections[entrance] - connecting_entrances = [x for x in potentials[enabling_region] if x != entrance and x not in dead_entrances and x not in drop_entrances_allowance] + check_list = list(potentials[enabling_region]) + if enabling_region.name in ['Desert Ledge', 'Desert Palace Entrance (North) Spot']: + alternate = 'Desert Palace Entrance (North) Spot' if enabling_region.name == 'Desert Ledge' else 'Desert Ledge' + check_list.extend(potentials[world.get_region(alternate, player)]) + connecting_entrances = [x for x in check_list if x != entrance and x not in dead_entrances and x not in drop_entrances_allowance] connect_able = len(connecting_entrances) > 0 if is_destination and sector.branches() == 0: # builder.dead_ends += 1 @@ -1566,7 +1593,11 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barrier valid = global_pole.is_valid_choice(dungeon_map, builder_choice, test_set) assign_sector(switch_choice, builder_choice, crystal_switches, global_pole) return crystal_switches + if len(crystal_switches) == 0: + raise GenerationException('No crystal switches to assign') sector_list = list(crystal_switches) + if len(population) > len(sector_list): + raise GenerationException('Not enough crystal switch sectors for those needed') choices = random.sample(sector_list, k=len(population)) for i, choice in enumerate(choices): builder = dungeon_map[population[i]] @@ -1577,7 +1608,7 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barrier def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_sectors, crystal_barriers, global_pole): invalid_builders = [] for name, builder in dungeon_map.items(): - if builder.c_switch_present and not builder.c_locked: + if builder.c_switch_present and builder.c_switch_required and not builder.c_locked: invalid_builders.append(builder) while len(invalid_builders) > 0: valid_builders = [] @@ -1586,7 +1617,7 @@ def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_s reachable_crystals = defaultdict() for sector in builder.sectors: if sector.equations is None: - sector.equations = calc_sector_equations(sector, builder) + sector.equations = calc_sector_equations(sector) if sector.is_entrance_sector() and not sector.destination_entrance: need_switch = True for region in sector.get_start_regions(): @@ -1620,7 +1651,7 @@ def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_s valid, sector, which_list = False, None, None while not valid: if len(candidates) <= 0: - raise GenerationException(f'need to provide more sophisticatedted crystal connection for {entrance_sector}') + raise GenerationException(f'need to provide more sophisticated crystal connection for {entrance_sector}') sector, which_list = random.choice(list(candidates.items())) del candidates[sector] valid = global_pole.is_valid_choice(dungeon_map, builder, [sector]) @@ -1679,7 +1710,7 @@ def find_pol_cand_for_c_switch(access, reachable_crystals, polarized_candidates) def pol_cand_matches_access_reach(sector, access, reachable_crystals): if sector.equations is None: - sector.equations = calc_sector_equations(sector, None) + sector.equations = calc_sector_equations(sector) for eq in sector.equations: key, cost_door = eq.cost if key in access.keys() and access[key]: @@ -1701,7 +1732,7 @@ def find_crystal_cand(access, crystal_switches): def crystal_cand_matches_access(sector, access): if sector.equations is None: - sector.equations = calc_sector_equations(sector, None) + sector.equations = calc_sector_equations(sector) for eq in sector.equations: key, cost_door = eq.cost if key in access.keys() and access[key] and eq.c_switch and len(sector.outstanding_doors) > 1: @@ -1973,6 +2004,9 @@ def polarity_step_3(dungeon_map, polarized_sectors, global_pole): sample_target = 100 if combos > 10 else combos * 2 while best_choices is None or samples < sample_target: samples += 1 + if len(odd_candidates) < len(odd_builders): + raise GenerationException(f'Unable to fix dungeon parity - not enough candidates.' + f' Ref: {next(iter(odd_builders)).name}') choices = random.sample(odd_candidates, k=len(odd_builders)) valid = global_pole.is_valid_multi_choice(dungeon_map, odd_builders, choices) charge = calc_total_charge(dungeon_map, odd_builders, choices) @@ -2633,7 +2667,7 @@ def valid_entrance(builder, sector_list, builder_info): if len(builder.sectors) == 0: is_dead_end = True else: - entrances, splits, world, player = builder_info + entrances, splits, c_tuple, world, player = builder_info if builder.name not in entrances.keys(): name_parts = builder.name.rsplit(' ', 1) entrance_list = splits[name_parts[0]][name_parts[1]] @@ -2646,8 +2680,8 @@ def valid_entrance(builder, sector_list, builder_info): for sector in entrances: for region in entrance_list: if region in sector.region_set(): - portal = next((x for x in world.dungeon_portals[player] if x.door.entrance.parent_region.name == region)) - if not portal.deadEnd: + portal = next((x for x in world.dungeon_portals[player] if x.door.entrance.parent_region.name == region), None) + if portal and not portal.deadEnd: all_dead = False break if not all_dead: @@ -2765,10 +2799,10 @@ def split_dungeon_builder(builder, split_list, builder_info): continue elif len(split_entrances) <= 0: continue - x, y, world, player = builder_info + ents, splits, c_tuple, world, player = builder_info r_name = split_entrances[0] - p = next(x for x in world.dungeon_portals[player] if x.door.entrance.parent_region.name == r_name) - if not p.deadEnd: + p = next((x for x in world.dungeon_portals[player] if x.door.entrance.parent_region.name == r_name), None) + if p and not p.deadEnd: candidates.append(name) merge_keys = random.sample(candidates, merge_attempt+1) if len(candidates) >= merge_attempt+1 else [] for name, split_entrances in split_list.items(): @@ -2782,6 +2816,7 @@ def split_dungeon_builder(builder, split_list, builder_info): sub_builder.all_entrances.extend(split_entrances) if key not in dungeon_map: dungeon_map[key] = sub_builder = DungeonBuilder(key) + sub_builder.split_flag = True sub_builder.all_entrances = list(split_entrances) for r_name in split_entrances: assign_sector(find_sector(r_name, candidate_sectors), sub_builder, candidate_sectors, global_pole) @@ -2799,6 +2834,9 @@ def split_dungeon_builder(builder, split_list, builder_info): def balance_split(candidate_sectors, dungeon_map, global_pole, builder_info): + dungeon_entrances, split_dungeon_entrances, connections_tuple, world, player = builder_info + for name, builder in dungeon_map.items(): + calc_allowance_and_dead_ends(builder, connections_tuple, world, player) comb_w_replace = len(dungeon_map) ** len(candidate_sectors) if comb_w_replace <= 10000: combinations = list(itertools.product(dungeon_map.keys(), repeat=len(candidate_sectors))) @@ -2937,12 +2975,13 @@ def check_for_forced_crystal_single(builder, candidate_sectors): for hook in builder_doors.keys(): for door in builder_doors[hook].keys(): opp = opposite_h_type(hook) - for d, sector in builder_doors[opp].items(): - if d != door and (not sector.blue_barrier or sector.c_switch): - return False - for d, sector in candidate_doors[opp].items(): - if not sector.blue_barrier or sector.c_switch: - return False + if opp in builder_doors.keys(): + for d, sector in builder_doors[opp].items(): + if d != door and (not sector.blue_barrier or sector.c_switch): + return False + for d, sector in candidate_doors[opp].items(): + if not sector.blue_barrier or sector.c_switch: + return False return True @@ -3217,7 +3256,7 @@ def identify_branching_issues(dungeon_map, builder_info): def check_for_valid_layout(builder, sector_list, builder_info): - dungeon_entrances, split_dungeon_entrances, world, player = builder_info + dungeon_entrances, split_dungeon_entrances, c_tuple, world, player = builder_info if builder.name in split_dungeon_entrances.keys(): try: temp_builder = DungeonBuilder(builder.name) @@ -3633,14 +3672,14 @@ def copy_door_equations(builder, sector_list): for sector in builder.sectors + sector_list: if sector.equations is None: # todo: sort equations? - sector.equations = calc_sector_equations(sector, builder) + sector.equations = calc_sector_equations(sector) curr_list = equations[sector] = [] for equation in sector.equations: curr_list.append(equation.copy()) return equations -def calc_sector_equations(sector, builder): +def calc_sector_equations(sector): equations = [] is_entrance = sector.is_entrance_sector() and not sector.destination_entrance if is_entrance: @@ -3670,6 +3709,8 @@ def calc_door_equation(door, sector, look_for_entrance): eq.benefit[hook_from_door(door)].append(door) eq.required = True eq.c_switch = door.crystal == CrystalBarrier.Either + # exceptions for long entrances ??? + # if door.name in ['PoD Dark Alley']: eq.entrance_flag = True return eq, flag eq = DoorEquation(door) diff --git a/Dungeons.py b/Dungeons.py index c33b38e8..9229140c 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -213,8 +213,8 @@ pod_regions = [ 'PoD Map Balcony', 'PoD Conveyor', 'PoD Mimics 1', 'PoD Jelly Hall', 'PoD Warp Hint', 'PoD Warp Room', 'PoD Stalfos Basement', 'PoD Basement Ledge', 'PoD Big Key Landing', 'PoD Falling Bridge', 'PoD Falling Bridge Ledge', 'PoD Dark Maze', 'PoD Big Chest Balcony', 'PoD Compass Room', 'PoD Dark Basement', - 'PoD Harmless Hellway', 'PoD Mimics 2', 'PoD Bow Statue', 'PoD Dark Pegs', 'PoD Lonely Turtle', 'PoD Turtle Party', - 'PoD Dark Alley', 'PoD Callback', 'PoD Boss', 'Palace of Darkness Portal' + 'PoD Harmless Hellway', 'PoD Mimics 2', 'PoD Bow Statue', 'PoD Bow Statue Moving Wall', 'PoD Dark Pegs', 'PoD Dark Pegs Ladder', 'PoD Dark Pegs Switch', + 'PoD Lonely Turtle', 'PoD Turtle Party', 'PoD Dark Alley', 'PoD Callback', 'PoD Boss', 'Palace of Darkness Portal' ] swamp_regions = [ diff --git a/EntranceShuffle.py b/EntranceShuffle.py index f5ed8a9f..9a20df7a 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -3616,7 +3616,7 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Sanctuary Grave', 'Sewer Drop'), ('Sanctuary Exit', 'Sanctuary Area'), - ('Old Man Cave (West)', 'Old Man Cave'), + ('Old Man Cave (West)', 'Old Man Cave Ledge'), ('Old Man Cave (East)', 'Old Man Cave'), ('Old Man Cave Exit (West)', 'Death Mountain Entrance'), ('Old Man Cave Exit (East)', 'West Death Mountain (Bottom)'), @@ -3762,7 +3762,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Two Brothers House (West)', 'Two Brothers House'), ('Two Brothers House Exit (East)', 'Light World'), ('Two Brothers House Exit (West)', 'Maze Race Ledge'), - ('Sanctuary', 'Sanctuary'), + ('Sanctuary', 'Sanctuary Portal'), ('Sanctuary Grave', 'Sewer Drop'), ('Sanctuary Exit', 'Light World'), ('Old Man House (Bottom)', 'Old Man House'), @@ -3833,7 +3833,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Old Man Cave Exit (West)', 'West Dark World'), ('Old Man Cave Exit (East)', 'Dark Death Mountain'), ('Dark Death Mountain Fairy', 'Old Man Cave'), - ('Bumper Cave (Bottom)', 'Old Man Cave'), + ('Bumper Cave (Bottom)', 'Old Man Cave Ledge'), ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), ('Bumper Cave Exit (Bottom)', 'Light World'), diff --git a/Gui.py b/Gui.py index 66fd4999..4cc5b106 100755 --- a/Gui.py +++ b/Gui.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import json import os import sys diff --git a/ItemList.py b/ItemList.py index d8f85dd8..c9d2d96d 100644 --- a/ItemList.py +++ b/ItemList.py @@ -749,6 +749,12 @@ def fill_specific_items(world): all_state = world.get_all_state(True) fill_restrictive(world, all_state, [cage], [key_item]) + location = world.get_location('Tower of Hera - Map Chest', 1) + key_item = next(x for x in world.itempool if 'Byrna' in x.name) + world.itempool.remove(key_item) + fast_fill(world, [key_item], [location]) + + # somaria = next(item for item in world.itempool if item.name == 'Cane of Somaria') # shooter = world.get_location('Palace of Darkness - Shooter Room', 1) # world.itempool.remove(somaria) diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 5b690c22..becf6bf8 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -335,8 +335,9 @@ def adjust_locations_rules(key_logic, rule, accessible_loc, key_layout, key_coun test_set = None needed = rule.needed_keys_w_bk if needed > 0: - accessible_loc.update(key_counter.other_locations) - blocked_loc = key_layout.all_locations-accessible_loc + all_accessible = set(accessible_loc) + all_accessible.update(key_counter.other_locations) + blocked_loc = key_layout.all_locations-all_accessible for location in blocked_loc: if location not in key_logic.location_rules.keys(): loc_rule = LocationRule() @@ -373,11 +374,16 @@ def refine_placement_rules(key_layout, max_ctr): rule.needed_keys_w_bk -= len(key_onlys) if rule.needed_keys_w_bk == 0: rules_to_remove.append(rule) - if rule.bk_relevant and len(rule.check_locations_w_bk) == rule.needed_keys_w_bk + 1: - new_restricted = set(max_ctr.free_locations) - rule.check_locations_w_bk - if len(new_restricted - key_logic.bk_restricted) > 0: - key_logic.bk_restricted.update(new_restricted) # bk must be in one of the check_locations - changed = True + # todo: evaluate this usage + # if rule.bk_relevant and len(rule.check_locations_w_bk) == rule.needed_keys_w_bk + 1: + # new_restricted = set(max_ctr.free_locations) - rule.check_locations_w_bk + # if len(new_restricted | key_logic.bk_restricted) < len(key_layout.all_chest_locations): + # if len(new_restricted - key_logic.bk_restricted) > 0: + # key_logic.bk_restricted.update(new_restricted) # bk must be in one of the check_locations + # changed = True + # else: + # rules_to_remove.append(rule) + # changed = True if rule.needed_keys_w_bk > key_layout.max_chests or len(rule.check_locations_w_bk) < rule.needed_keys_w_bk: logging.getLogger('').warning('Invalid rule - what went wrong here??') rules_to_remove.append(rule) @@ -501,6 +507,8 @@ def find_bk_locked_sections(key_layout, world, player): key_layout.all_chest_locations.update(counter.free_locations) key_layout.item_locations.update(counter.free_locations) key_layout.item_locations.update(counter.key_only_locations) + key_layout.all_locations.update(key_layout.item_locations) + key_layout.all_locations.update(counter.other_locations) if counter.big_key_opened and counter.important_location: big_chest_allowed_big_key = False if not counter.big_key_opened: diff --git a/Main.py b/Main.py index 06c8228b..42a45fdd 100644 --- a/Main.py +++ b/Main.py @@ -17,7 +17,7 @@ from InvertedRegions import create_inverted_regions, mark_dark_world_regions from EntranceShuffle import link_entrances, link_inverted_entrances from Rom import patch_rom, patch_race_rom, patch_enemizer, apply_rom_settings, LocalRom, JsonRom, get_hash_string from Doors import create_doors -from DoorShuffle import link_doors, connect_portal_copy +from DoorShuffle import link_doors, connect_portal from RoomData import create_rooms from Rules import set_rules from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive @@ -25,7 +25,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute from ItemList import generate_itempool, difficulties, fill_prizes, fill_specific_items from Utils import output_path, parse_player_names -__version__ = '0.2.0.17u' +__version__ = '0.3.0.2-u' class EnemizerError(RuntimeError): pass @@ -114,7 +114,7 @@ def main(args, seed=None, fish=None): create_dungeons(world, player) adjust_locations(world, player) - if any(world.potshuffle): + if any(world.potshuffle.values()): logger.info(world.fish.translate("cli", "cli", "shuffling.pots")) for player in range(1, world.players + 1): if world.potshuffle[player]: @@ -222,9 +222,6 @@ def main(args, seed=None, fish=None): if use_enemizer: base_patch = LocalRom(args.rom) # update base2current.json - if use_enemizer: - base_patch = LocalRom(args.rom) # update base2current.json - rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom) if use_enemizer and (args.enemizercli or not args.jsonout): @@ -436,9 +433,7 @@ def copy_world(world): copied_region.is_light_world = region.is_light_world copied_region.is_dark_world = region.is_dark_world copied_region.dungeon = region.dungeon - copied_region.locations = [copy.copy(location) for location in region.locations] - for location in copied_region.locations: - location.parent_region = copied_region + copied_region.locations = [ret.get_location(location.name, location.player) for location in region.locations] for entrance in region.entrances: ret.get_entrance(entrance.name, entrance.player).connect(copied_region) @@ -482,7 +477,7 @@ def copy_world(world): ret.dungeon_portals = world.dungeon_portals for player, portals in world.dungeon_portals.items(): for portal in portals: - connect_portal_copy(portal, ret, player) + connect_portal(portal, ret, player) ret.sanc_portal = world.sanc_portal for player in range(1, world.players + 1): diff --git a/README.md b/README.md index 5a224b15..46d692f5 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Doors are not shuffled. #### Level 1 Normal door and spiral staircases are shuffled #### Level 2 -Same as Level 1 plus open edges and straight staircases are shuffled. +Same as Level 1 plus open edges and both types of straight staircases are shuffled. #### Level 3 Same as Level 2 plus Dungeon Lobbies are shuffled @@ -60,9 +60,10 @@ Key drop location are added to the pool. The keys normally found there are added ### Mixed Travel (--mixed_travel value) Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are -otherwise unconnected logically can be reach using these glitches. To prevent the player from unintentionally +otherwise unconnected logically can be reached using these glitches. To prevent the player from unintentionally changing +dungeons while doing these tricks, you may use one of the following options. -#### Prevent +#### Prevent (default) Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning crossed dungeon mode to learn what is dangerous and what is not. No logic seeds ignore this setting. @@ -73,17 +74,17 @@ The rooms are left alone and it is up to the discretion of the player whether to #### Force -The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game. +The two disjointed sections are forced to be in the same dungeon but the glitches are never logically required to complete that game. ### Standardize Palettes (--standardize_palettes) No effect if door shuffle is not on crossed -#### Standardize +#### Standardize (default) Rooms in the same dungeon have their palettes changed to match. Hyrule Castle is split between Sewer and HC palette. -Rooms adjacent to sanctuary get their coloring to match sanc. +Rooms adjacent to sanctuary get their coloring to match the Sanctuary's original palette. #### Original -Room keep their original palettes. +Rooms/supertiles keep their original palettes. ## Map/Compass/Small Key/Big Key shuffle (aka Keysanity) @@ -121,13 +122,31 @@ Use to batch generate multiple seeds with same settings. If a seed number is pro Show the help message and exit. ``` ---door_shuffle +--door_shuffle ``` For specifying the door shuffle you want as above. (default: basic) ``` ---intensity +--intensity ``` For specifying the door shuffle intensity level you want as above. (default: 2) + +``` +--keydropshuffle +``` + +Include mobs and pots drop in the item pool. (default: not enabled) + +``` +--mixed_travel +``` + +How to handle certain glitches in crossed dungeon mode. (default: prevent) + +``` +--standardize_palettes (mode) +``` + +Whether to standardize dungeon palettes in crossed dungeon mode. (default: standardize) \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 50f191b4..460d34ad 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,157 +1,22 @@ # New Features -## Lobby shuffle added as Intensity level 3 +## In-Room Staircases/Ladders -* Standard notes: - * The sanctuary is vanilla, and will be missing the exit door until Zelda is rescued - * In entrance shuffle the hyrule castle left and right exit door will be missing until Zelda is rescued. This - replaces the rails that used to block those lobby exits - * In non-entrance shuffle, Agahnims tower can be in logic if you have cape and/or Master sword, but you are never - required to beat Agahnim 1 until Zelda is rescued. -* Open notes: - * The Sanctuary is limited to be in a LW dungeon unless you have ER Crossed or higher enabled - * Mirroring from the Sanctuary to the new "Sanctuary" lobby is now in logic, as is exiting there. - * In ER crossed or higher, if the Sanctuary is in the Dark World, Link starts as Bunny there until the Moon Pearl - is found. Nothing inside that dungeon is in logic until the Moon Pearl is found. (Unless it is a multi-entrance - dungeon that you can access from some LW entrance) -* Lobby list is found in the spoiler -* Exits for Multi-entrance dungeons after beating bosses now makes more sense. Generally you'll exit from a entrance - from which the boss can logically be reached. If there are multiple, ones that do not lead to regions only accessible - by connector are preferred. The exit is randomly chosen if there's no obvious preference. However, In certain poor - cases like Skull Woods in ER, sometimes an exit is chosen not because you can reach the boss from there, but to - prevent a potential forced S&Q. -* Palette changes: - * Certain doors/transition no longer have an effect on the palette choice (dead ends mostly or just bridges) - * Sanctuary palette used on the adjacent rooms to Sanctuary (Sanctuary stays the dungeon color for now) - * Sewer palette comes back for part of Hyrule Castle for areas "near" the sewer dropdown - * There is a setting to keep original palettes (--standardize_palettes original) -* Known issues: - * Palettes aren't perfect - * Some ugly colors - * Invisible floors can be see in many palettes +In intensity level 2 and higher the in-floor staircases/ladders that take you between tiles can now be shuffled with +any N/S connections. (those that appear to go up one floor are North connection and those that go down are South ones) -## Key Drop Shuffle - ---keydropshuffle added. This add 33 new locations to the game where keys are found under pots -and where enemies drop keys. This includes 32 small key location and the ball and chain guard who normally drop the HC -Big Key. - -* Overall location count updated -* Setting mentioned in spoiler -* Minor change: if a key is Universal or for that dungeon, then if will use the old mechanics of picking up the key without -an entire pose and should be obtainable with the hookshot or boomerang as before - -## --mixed_travel setting -* Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are -otherwise unconnected logically can be reach using these glitches. To prevent the player from unintentionally - * prevent: Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning - crossed dungeon mode to learn what is dangerous and what is not. No logic seeds ignore this setting. - * allow: The rooms are left alone and it is up to the discretion of the player whether to use these tricks or not. - * force: The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game. - -## Keysanity menu redesign - -Redesign of Keysanity Menu complete for crossed dungeon and moved out of experimental. -* First screen about Big Keys and Small Keys - * 1st Column: The map is required for information about the Big Key - * If you don't have the map, it'll be blank until you obtain the Big Key - * If have the map: - * 0 indicates there is no Big Key for that dungeon - * A red symbol indicates the Ball N Chain guard has the big key for that dungeon (does not apply in - --keydropshuffle) - * Blank if there a big key but you haven't found it yet - * 2nd Column displays the current number of keys for that dungeon. Suppressed in retro (always blank) - * 3rd Column only display if you have the map. It shows the number of keys left to collect for that dungeon. If - --keydropshuffle is off, this does not count key drops. If on, it does. - * (Note: the key columns can display up to 36 using the letters A-Z after 9) -* Second screen about Maps / Compass - * 1st Column: indicate if you have foudn the map of not for that dungeon - * 2nd and 3rd Column: You must have the compass to see these columns. A two-digit display that show you how - many chests are left in the dungeon. If -keydropshuffle is off, this does not count key drop. If on, it does. - -## Potshuffle by compiling - -Same flag as before but uses python logic written by compiling instead of the enemizer logic-less version. Needs some -testing to verify logic is all good. - -## Other features - -### Spoiler log improvements - -* In crossed mode, the new dungeon is listed along with the location designated by a '@' sign -* Random gt crystals and ganon crystal are noted in the settings for better reproduction of seeds - -### Experimental features - -* Only the random bomb doors and the item counter are currently experimental - * Item counter is suppressed in Triforce Hunt - -#### Temporary debug features - -* Removed the red square in the upper right corner of the hud if the castle gate is closed +Big thanks to Catobat for doing all the hard work. # Bug Fixes -* 2.0.17u - * Generation improvements -* 2.0.16u - * Prevent HUD from showing key counter when in the overworld. (Aga 2 doesn't always clear the dungeon indicator) - * Fixed key logic regarding certain isolated "important" locations - * Fixed a problem with keydropshuffle thinking certain progression items are keys - * A couple of inverted rules fixed - * A more accurate count of which locations are blocked by teh big key in Ganon's Tower - * Updated base rom to 31.0.7 (includes potential hera basement cage fix) -* 2.0.15u - * Allow Aga Tower lobby door as a a paired keydoor (typo) - * Fix portal check for multi-entrance dungeons -* 2.0.14u - * Removal of key doors no longer messes up certain lobbies - * Fixed ER entrances when Desert Back is a connector -* 2.0.13u - * Minor portal re-work for certain logic and spoiler information - * Repaired certain exits wrongly affected by Sanctuary placement (ER crossed + intensity 3) - * Fix for inverted ER + intensity 3 - * Fix for current small keys missing on keysanity menu - * Logic added for cases where you can flood Swamp Trench 1 before finding flippers and lock yourself out of getting - something behind the trench that leads to the flippers -* 2.0.12u - * Another fix for animated tiles (fairy fountains) - * GT Big Key stat fixed on credits - * Any denomination of rupee 20 or below can be removed to make room for Crossed Dungeon's extra dungeon items. This - helps retro generate more often. - * Fix for TR Lobbies in intensity 3 and ER shuffles that was causing a hardlock - * Standard ER logic revised for lobby shuffle and rain state considerations. -* 2.0.11u - * Fix output path setting in settings.json - * Fix trock entrances when intensity <= 2 -* 2.0.10u - * Fix POD, TR, GT and SKULL 3 entrances if sanc ends up in that dungeon in crossed ER+ - * TR Lobbies that need a bomb and can be entered before bombing should be pre-opened - * Animated tiles are loaded correctly in lobbies - * If a wallmaster grabs you and the lobby is dark, the lamp turns on now - * Certain key rules no longer override item requirements (e.g. Somaria behind TR Hub) - * Old Man Cave is correctly one way in the graph - * Some key logic fixes -* 2.0.9-u - * /missing command in MultiClient fixed -* 2.0.8-u - * Player sprite disappears after picking up a key drop in keydropshuffle - * Sewers and Hyrule Castle compass problems - * Double count of the Hera Basement Cage item (both overall and compass) - * Unnecessary/inconsistent rug cutoff - * TR Crystal Maze thought you get through backwards without Somaria - * Ensure Thieves Attic Window area can always be reached - * Fixed where HC big key was not counted -* Prior fixes - * Fixed a situation where logic did not account properly for Big Key doors in standard Hyrule Castle - * Fixed a problem ER shuffle generation that did not account for lobbies moving around - * Fixed a problem with camera unlock (GT Mimics and Mire Minibridge) - * Fixed a problem with bad-pseudo layer at PoD map Balcony (unable to hit switch with Bomb) - * Fixed a problem with the Ganon hint when hints are turned off +* 0.3.0.1-u + * Problem with lobbies on re-rolls corrected + * Potential playthrough problem addressed +* 0.3.0.0-u + * Generation improvements. Basic >95% success. Crossed >80% success. + * Possible increased generation times as certain generation problem tries a partial re-roll # Known Issues -* Multiworld = /missing command not working -* Potenial keylocks in multi-entrance dungeons -* Incorrect vanilla keylogic for Mire -* ER - Potential for Skull Woods West to be completely inaccessible in non-beatable logic \ No newline at end of file +* Potential keylocks in multi-entrance dungeons +* Incorrect vanilla key logic for Mire \ No newline at end of file diff --git a/Regions.py b/Regions.py index 2bee78e6..dd1c7d1c 100644 --- a/Regions.py +++ b/Regions.py @@ -511,8 +511,11 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'PoD Dark Basement', 'Palace of Darkness', ['Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right'], ['PoD Dark Basement W Up Stairs', 'PoD Dark Basement E Up Stairs']), create_dungeon_region(player, 'PoD Harmless Hellway', 'Palace of Darkness', ['Palace of Darkness - Harmless Hellway'], ['PoD Harmless Hellway NE', 'PoD Harmless Hellway SE']), create_dungeon_region(player, 'PoD Mimics 2', 'Palace of Darkness', None, ['PoD Mimics 2 SW', 'PoD Mimics 2 NW']), - create_dungeon_region(player, 'PoD Bow Statue', 'Palace of Darkness', None, ['PoD Bow Statue SW', 'PoD Bow Statue Down Ladder']), - create_dungeon_region(player, 'PoD Dark Pegs', 'Palace of Darkness', None, ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs WN']), + create_dungeon_region(player, 'PoD Bow Statue', 'Palace of Darkness', None, ['PoD Bow Statue SW', 'PoD Bow Statue Crystal Path']), + create_dungeon_region(player, 'PoD Bow Statue Moving Wall', 'Palace of Darkness', None, ['PoD Bow Statue Moving Wall Path', 'PoD Bow Statue Down Ladder', 'PoD Bow Statue Moving Wall Cane Path']), + create_dungeon_region(player, 'PoD Dark Pegs', 'Palace of Darkness', None, ['PoD Dark Pegs Hammer Path', 'PoD Dark Pegs WN']), + create_dungeon_region(player, 'PoD Dark Pegs Ladder', 'Palace of Darkness', None, ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs Ladder Cane Path']), + create_dungeon_region(player, 'PoD Dark Pegs Switch', 'Palace of Darkness', None, ['PoD Dark Pegs Switch Path']), create_dungeon_region(player, 'PoD Lonely Turtle', 'Palace of Darkness', None, ['PoD Lonely Turtle SW', 'PoD Lonely Turtle EN']), create_dungeon_region(player, 'PoD Turtle Party', 'Palace of Darkness', None, ['PoD Turtle Party ES', 'PoD Turtle Party NW']), create_dungeon_region(player, 'PoD Dark Alley', 'Palace of Darkness', None, ['PoD Dark Alley NE']), @@ -555,9 +558,9 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Swamp Right Elbow', 'Swamp Palace', None, ['Swamp Right Elbow SE', 'Swamp Right Elbow Down Stairs']), create_dungeon_region(player, 'Swamp Drain Left', 'Swamp Palace', None, ['Swamp Drain Left Up Stairs', 'Swamp Drain WN']), create_dungeon_region(player, 'Swamp Drain Right', 'Swamp Palace', ['Swamp Drain'], ['Swamp Drain Right Switch', 'Swamp Drain Right Up Stairs']), - # This is intentionally odd so I don't have to treat the WS door in the Flooded Room oddly (because of how it works when going backward) - create_dungeon_region(player, 'Swamp Flooded Room', 'Swamp Palace', None, ['Swamp Flooded Room Up Stairs', 'Swamp Flooded Room Ladder', 'Swamp Flooded Room WS']), - create_dungeon_region(player, 'Swamp Flooded Spot', 'Swamp Palace', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right'], ['Swamp Flooded Spot Ladder']), + create_dungeon_region(player, 'Swamp Flooded Room', 'Swamp Palace', None, ['Swamp Flooded Room Up Stairs', 'Swamp Flooded Room Ladder']), + # this is more normal and allows getting the chests from doing this room backward in logic + create_dungeon_region(player, 'Swamp Flooded Spot', 'Swamp Palace', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right'], ['Swamp Flooded Room WS', 'Swamp Flooded Spot Ladder']), create_dungeon_region(player, 'Swamp Basement Shallows', 'Swamp Palace', None, ['Swamp Basement Shallows NW', 'Swamp Basement Shallows EN', 'Swamp Basement Shallows ES']), create_dungeon_region(player, 'Swamp Waterfall Room', 'Swamp Palace', ['Swamp Palace - Waterfall Room'], ['Swamp Waterfall Room SW', 'Swamp Waterfall Room NW', 'Swamp Waterfall Room NE']), create_dungeon_region(player, 'Swamp Refill', 'Swamp Palace', None, ['Swamp Refill SW']), @@ -872,7 +875,8 @@ def create_dungeon_regions(world, player): world.get_region('PoD Arena Main', player).crystal_switch = True world.get_region('PoD Arena Bridge', player).crystal_switch = True # RANGED Weapon Required world.get_region('PoD Sexy Statue', player).crystal_switch = True - world.get_region('PoD Bow Statue', player).crystal_switch = True # LADDER not accessible (maybe with cane) + world.get_region('PoD Bow Statue', player).crystal_switch = True + world.get_region('PoD Dark Pegs Switch', player).crystal_switch = True world.get_region('PoD Dark Pegs', player).crystal_switch = True world.get_region('Swamp Crystal Switch', player).crystal_switch = True world.get_region('Thieves Spike Switch', player).crystal_switch = True diff --git a/Rom.py b/Rom.py index ff65fec3..4b97fc4e 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '185a0f74ab0e2ce8899c8d7d309ca68c' +RANDOMIZERBASEHASH = 'bffd4e834049ca5f5295601436fc6009' class JsonRom(object): @@ -284,14 +284,23 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_ with open(options_path, 'w') as f: json.dump(options, f) - subprocess.check_call([os.path.abspath(enemizercli), - '--rom', baserom_path, - '--seed', str(world.rom_seeds[player]), - '--base', basepatch_path, - '--randomizer', randopatch_path, - '--enemizer', options_path, - '--output', enemizer_output_path], - cwd=os.path.dirname(enemizercli), stdout=subprocess.DEVNULL) + try: + subprocess.run([os.path.abspath(enemizercli), + '--rom', baserom_path, + '--seed', str(world.rom_seeds[player]), + '--base', basepatch_path, + '--randomizer', randopatch_path, + '--enemizer', options_path, + '--output', enemizer_output_path], + cwd=os.path.dirname(enemizercli), + check=True, + capture_output=True) + except subprocess.CalledProcessError as e: + from Main import EnemizerError + enemizerMsg = world.fish.translate("cli","cli","Enemizer returned exit code: ") + str(e.returncode) + "\n" + enemizerMsg += world.fish.translate("cli","cli","enemizer.nothing.applied") + logging.error(f'Enemizer error output: {e.stderr.decode("utf-8")}\n') + raise EnemizerError(enemizerMsg) with open(enemizer_basepatch_path, 'r') as f: for patch in json.load(f): @@ -676,7 +685,7 @@ def patch_rom(world, rom, player, team, enemized): for door in world.doors: if door.dest is not None and isinstance(door.dest, Door) and\ door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs, - DoorType.Open, DoorType.StraightStairs]: + DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: rom.write_bytes(door.getAddress(), door.dest.getTarget(door)) for paired_door in world.paired_doors[player]: rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player)) @@ -684,13 +693,15 @@ def patch_rom(world, rom, player, team, enemized): if world.doorShuffle[player] != 'vanilla': for builder in world.dungeon_layouts[player].values(): - if builder.pre_open_stonewall: - if builder.pre_open_stonewall.name == 'Desert Wall Slide NW': + for stonewall in builder.pre_open_stonewalls: + if stonewall.name == 'Desert Wall Slide NW': dr_flags |= DROptions.Open_Desert_Wall + elif stonewall.name == 'PoD Bow Statue Down Ladder': + dr_flags |= DROptions.Open_PoD_Wall for name, pair in boss_indicator.items(): dungeon_id, boss_door = pair opposite_door = world.get_door(boss_door, player).dest - if opposite_door and opposite_door.roomIndex > -1: + if opposite_door and isinstance(opposite_door, Door) and opposite_door.roomIndex > -1: dungeon_name = opposite_door.entrance.parent_region.dungeon.name dungeon_id = boss_indicator[dungeon_name][0] rom.write_byte(0x13f000+dungeon_id, opposite_door.roomIndex) @@ -1375,38 +1386,42 @@ def patch_rom(world, rom, player, team, enemized): rom.write_bytes(0x6D2FB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E]) rom.write_bytes(0x6D313, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E]) - rom.write_byte(0x18004E, 0) # Escape Fill (nothing) - write_int16(rom, 0x180183, 300) # Escape fill rupee bow - 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) + rom.write_byte(0x18004E, 0) # Escape Fill (nothing) + write_int16(rom, 0x180183, 300) # Escape fill rupee bow + 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) bow_max, bomb_max, magic_max = 0, 0, 0 + bow_small, magic_small = 0, 0 if world.mode[player] == 'standard': if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']: - rom.write_byte(0x18004E, 1) # Escape Fill (arrows) - write_int16(rom, 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) - bow_max = 70 + rom.write_byte(0x18004E, 1) # Escape Fill (arrows) + write_int16(rom, 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) + bow_max, bow_small = 70, 10 elif uncle_location.item is not None and 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) + 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) bomb_max = 50 elif uncle_location.item is not None and 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) - rom.write_bytes(0x18018B, [0x20,0,0]) # Mantle respawn refills (magic, bombs, arrows) - magic_max = 0x80 + 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) + rom.write_bytes(0x18018B, [0x20, 0, 0]) # Mantle respawn refills (magic, bombs, arrows) + magic_max, magic_small = 0x80, 0x20 if world.doorShuffle[player] == 'crossed': # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180185, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)]) rom.write_bytes(0x180188, [0x20, 3, 10]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0x20, 3, 10]) # Mantle respawn refills (magic, bombs, arrows) - + elif world.doorShuffle[player] == 'basic': # just in case a bomb is needed to get to a chest + rom.write_bytes(0x180185, [max(0x00, magic_max), max(3, bomb_max), max(0, bow_max)]) + rom.write_bytes(0x180188, [magic_small, 3, bow_small]) # Zelda respawn refills (magic, bombs, arrows) + rom.write_bytes(0x18018B, [magic_small, 3, bow_small]) # Mantle respawn refills (magic, bombs, arrows) # patch swamp: Need to enable permanent drain of water as dam or swamp were moved rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required[player] else 0x00) @@ -2575,4 +2590,4 @@ def write_pots_to_rom(rom, pot_contents): write_int16(rom, pot_item_room_table_lookup + 2*i, n-2) else: write_int16(rom, pot_item_room_table_lookup + 2*i, n-2) - assert n <= pot_item_table_end \ No newline at end of file + assert n <= pot_item_table_end diff --git a/RoomData.py b/RoomData.py index ac740c90..3fe8d594 100644 --- a/RoomData.py +++ b/RoomData.py @@ -254,6 +254,12 @@ def create_rooms(world, player): world.get_room(0xc0, player).change(0, DoorKind.Normal) # fix this kill room if enemizer is on +def reset_rooms(world, player): + world.rooms = [x for x in world.rooms if x.player != player] + world._room_cache.clear() + create_rooms(world, player) + + class Room(object): def __init__(self, player, index, address): self.player = player diff --git a/Rules.py b/Rules.py index f884c2af..1b505d6b 100644 --- a/Rules.py +++ b/Rules.py @@ -202,8 +202,10 @@ def global_rules(world, player): set_rule(world.get_entrance('PoD Mimics 2 NW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Bow Statue Down Ladder', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Map Balcony Drop Down', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('PoD Dark Pegs WN', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('PoD Dark Pegs Up Ladder', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Ladder Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Ladder Cane Path', player), lambda state: state.has('Cane of Somaria', player)) + set_rule(world.get_entrance('PoD Bow Statue Moving Wall Cane Path', player), lambda state: state.has('Cane of Somaria', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize', player)) @@ -231,10 +233,9 @@ def global_rules(world, player): set_rule(world.get_entrance('Swamp Barrier Ledge Hook Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Swamp Drain Right Switch', player), lambda state: state.has('Drained Swamp', player)) set_rule(world.get_entrance('Swamp Drain WN', player), lambda state: state.has('Drained Swamp', player)) + # this might be unnecesssary for an insanity style shuffle set_rule(world.get_entrance('Swamp Flooded Room WS', player), lambda state: state.has('Drained Swamp', player)) set_rule(world.get_entrance('Swamp Flooded Room Ladder', player), lambda state: state.has('Drained Swamp', player)) - set_rule(world.get_location('Swamp Palace - Flooded Room - Left', player), lambda state: state.has('Drained Swamp', player)) - set_rule(world.get_location('Swamp Palace - Flooded Room - Right', player), lambda state: state.has('Drained Swamp', player)) set_rule(world.get_entrance('Swamp Flooded Spot Ladder', player), lambda state: state.has('Flippers', player) or state.has('Drained Swamp', player)) set_rule(world.get_entrance('Swamp Drain Left Up Stairs', player), lambda state: state.has('Flippers', player) or state.has('Drained Swamp', player)) set_rule(world.get_entrance('Swamp Waterway NW', player), lambda state: state.has('Flippers', player)) @@ -854,7 +855,9 @@ def no_glitches_rules(world, player): 'PoD Callback': {'sewer': False, 'entrances': ['PoD Callback WS', 'PoD Callback Warp'], 'locations': []}, 'PoD Turtle Party': {'sewer': False, 'entrances': ['PoD Turtle Party ES', 'PoD Turtle Party NW'], 'locations': []}, 'PoD Lonely Turtle': {'sewer': False, 'entrances': ['PoD Lonely Turtle SW', 'PoD Lonely Turtle EN'], 'locations': []}, - 'PoD Dark Pegs': {'sewer': False, 'entrances': ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs WN'], 'locations': []}, + 'PoD Dark Pegs': {'sewer': False, 'entrances': ['PoD Dark Pegs Hammer Path', 'PoD Dark Pegs WN'], 'locations': []}, + 'PoD Dark Pegs Ladder': {'sewer': False, 'entrances': ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs Ladder Cane Path'], 'locations': []}, + 'PoD Dark Pegs Switch': {'sewer': False, 'entrances': ['PoD Dark Pegs Switch Path'], 'locations': []}, 'PoD Dark Basement': {'sewer': False, 'entrances': ['PoD Dark Basement W Up Stairs', 'PoD Dark Basement E Up Stairs'], 'locations': ['Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right']}, 'PoD Dark Maze': {'sewer': False, 'entrances': ['PoD Dark Maze EN', 'PoD Dark Maze E'], 'locations': ['Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom']}, 'Eastern Dark Square': {'sewer': False, 'entrances': ['Eastern Dark Square NW', 'Eastern Dark Square Key Door WN', 'Eastern Dark Square EN'], 'locations': []}, diff --git a/Utils.py b/Utils.py index 18d46667..229573f2 100644 --- a/Utils.py +++ b/Utils.py @@ -36,6 +36,9 @@ def is_bundled(): return getattr(sys, 'frozen', False) def local_path(path): + # just do stuff here and bail + return os.path.join(".", path) + if local_path.cached_path is not None: return os.path.join(local_path.cached_path, path) @@ -51,6 +54,9 @@ def local_path(path): local_path.cached_path = None def output_path(path): + # just do stuff here and bail + return os.path.join(".", path) + if output_path.cached_path is not None: return os.path.join(output_path.cached_path, path) @@ -61,15 +67,7 @@ def output_path(path): # has been packaged, so cannot use CWD for output. if sys.platform == 'win32': #windows - import ctypes.wintypes - CSIDL_PERSONAL = 5 # My Documents - SHGFP_TYPE_CURRENT = 0 # Get current, not default value - - buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH) - ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PERSONAL, None, SHGFP_TYPE_CURRENT, buf) - - documents = buf.value - + documents = os.path.join(os.path.expanduser("~"),"Documents") elif sys.platform == 'darwin': from AppKit import NSSearchPathForDirectoriesInDomains # pylint: disable=import-error # http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains @@ -655,4 +653,3 @@ if __name__ == '__main__': # room_palette_data(old_rom=sys.argv[1]) # extract_data_from_us_rom(sys.argv[1]) extract_data_from_jp_rom(sys.argv[1]) - diff --git a/asm/doorrando.asm b/asm/doorrando.asm index 7de554fd..807095c7 100644 --- a/asm/doorrando.asm +++ b/asm/doorrando.asm @@ -7,6 +7,8 @@ ; Free RAM notes ; Normal doors use $AB-AC for scrolling indicator ; Normal doors use $FE to store the trap door indicator +; Normal doors use $045e to store Y coordinate when transitioning to in-room stairs +; Normal doors use $045f to determine the order in which supertile quadrants are drawn ; Spiral doors use $045e to store stair type ; Gfx uses $b1 to for sub-sub-sub-module thing @@ -35,7 +37,7 @@ incsrc edges.asm incsrc math.asm incsrc hudadditions.asm incsrc dr_lobby.asm -warnpc $279700 +warnpc $279C00 incsrc doortables.asm warnpc $288000 diff --git a/asm/doortables.asm b/asm/doortables.asm index 40276be2..2c0140ea 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -1,4 +1,4 @@ -org $279700 +org $279C00 KeyDoorOffset: ; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler dw $0000,$0001,$0003,$0000,$0006,$0000,$000b,$0000,$0000,$0000,$000c,$000d,$0010,$0011,$0012,$0000 @@ -58,7 +58,7 @@ db $9f org $27A000 DoorTable: -;; NW 00 N 01 N 02 WN 00 W 01 WS 02 SW 00 S 01 SE 02 EN 00 E 01 ES 02 - Door ruler +;; NW 00 N 01 NE 02 WN 00 W 01 WS 02 SW 00 S 01 SE 02 EN 00 E 01 ES 02 - Door ruler dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Default/Garbage row dw $0003, $0003, $0003, $0450, $0003, $0003, $0003, $0003, $0003, $0452, $0003, $0003 ; HC Back Hall (x01) dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Sewer Switches (x02) @@ -227,7 +227,7 @@ dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, ;dw $0080, $1f50 ; ->zelda's cellblock org $27B000 -SpiralTable: ;113 4 byte entries - should end at 27B44C +SpiralTable: ;113 4 byte entries - should end at 27B1C4 dw $0203, $8080 ;null row dw $0203, $8080 ;HC Backhallway dw $0203, $8080 ;Sewer Pull @@ -557,6 +557,20 @@ MultDivInfo: ; (1, 2, 3, 4, 5, 6, 10, 20) db $01, $02, $03, $04, $05, $06, $0a, $14 ; indices: 0-7 +; In-room stairs in North/South pairs. From left to right: +; PoD, IP right side, IP Freezor chest and GT +org $27C700 +InroomStairsTable: +dw $0003,$0003, $0003,$0003, $0003,$0003, $0003,$0003 + +org $27C720 +InroomStairsRoom: +db $0B,$1B, $3F,$1F, $7E,$5E, $96,$3D +InroomStairsX: +dw $0190, $0160, $0040, $0178 +InroomStairsY: +dw $0058, $0148, $0198, $0190 + ; dungeon tables ; HC HC EP DP AT SP PD MM SW IP TH TT TR GT diff --git a/asm/drhooks.asm b/asm/drhooks.asm index 43802ce7..1aa62dde 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -46,8 +46,19 @@ org $029396 ; <- 11396 - Bank02.asm : 3641 (LDA $01C322, X) jsl StraightStairLayerFix org $02c06d ; <- Bank02.asm : 9874 (LDX $0418, CMP.b #$02) jsl DoorToStraight : nop +org $02c092 ; STA $0020, Y : LDX #$00 +jsl DoorToInroom : nop +org $02c0f8 ; CMP $02C034, X +jsl DoorToInroomEnd org $02941a ; <- Bank02.asm : 3748 module 7.12.11 (LDA $0464 : BNE BRANCH_$11513 : INC $B0 : RTS) jsl StraightStairsTrapDoor : rts +org $028b54 ; <- Bank02.asm : 2200 (JSL UseImplicitRegIndexedLocalJumpTable) +jsl InroomStairsTrapDoor + +org $0289a0 ; JSL $0091C4 +jsl QuadrantLoadOrderBeforeScroll +org $02bd9c ; JSL $0091C4 +jsl QuadrantLoadOrderAfterScroll ; Graphics fix diff --git a/asm/edges.asm b/asm/edges.asm index 2b9c2228..58852b12 100644 --- a/asm/edges.asm +++ b/asm/edges.asm @@ -52,14 +52,20 @@ LoadEdgeRoomVert: lda $03 : sta $a0 sty $06 and.b #$f0 : lsr #3 : !sub $21 : !add $06 : sta $02 - ldy #$01 : jsr ShiftVariablesMainDir lda $04 : and #$80 : bne .edge lda $04 : sta $01 ; load up flags in $01 + and #$03 : cmp #$03 : beq .inroom + ldy #$01 : jsr ShiftVariablesMainDir jsr PrepScrollToNormal bra .scroll + .inroom + jsr ScrollToInroomStairs + rts + .edge + ldy #$01 : jsr ShiftVariablesMainDir lda $04 : and #$10 : beq + lda #$01 + sta $ee ; layer stuff diff --git a/asm/normal.asm b/asm/normal.asm index 5d8b6043..56fee909 100644 --- a/asm/normal.asm +++ b/asm/normal.asm @@ -31,6 +31,13 @@ WarpUp: jsr Cleanup rtl +; Checks if $a0 is equal to . If it is, opens its stonewall if it's there +macro StonewallCheck(Room) + lda $a0 : cmp.b # : bne ?end + lda.l *2+$7ef000 : ora #$80 : sta.l *2+$7ef000 + ?end +endmacro + WarpDown: lda.l DRMode : beq .end lda $040c : cmp.b #$ff : beq .end @@ -38,6 +45,7 @@ WarpDown: jsr CalcIndex !add #$0c : ldy #$ff ; offsets in A, Y jsr LoadRoomVert + %StonewallCheck($43) .end jsr Cleanup rtl @@ -130,15 +138,20 @@ LoadRoomVert: .gtg ;Good to Go! pla ; Throw away normal room (don't fill up the stack) lda $a0 : and.b #$F0 : lsr #3 : !sub $21 : !add $06 : sta $02 - ldy #$01 : jsr ShiftVariablesMainDir - lda $01 : and #$80 : beq .normal + lda $01 : and #$80 : beq .notEdge + ldy #$01 : jsr ShiftVariablesMainDir ldy $06 : cpy #$ff : beq + lda $01 : jsr LoadSouthMidpoint : bra ++ + lda $01 : jsr LoadNorthMidpoint ++ jsr PrepScrollToEdge : bra .scroll + .notEdge + lda $01 : and #$03 : cmp #$03 : bne .normal + jsr ScrollToInroomStairs + bra .end .normal + ldy #$01 : jsr ShiftVariablesMainDir jsr PrepScrollToNormal .scroll lda $01 : and #$40 : pha @@ -180,6 +193,68 @@ ShiftVariablesMainDir: rts } +; Normal Flags should be in $01 +ScrollToInroomStairs: +{ + jsr PrepScrollToInroomStairs + ldy #$01 : jsr ShiftVariablesMainDir + jsr ScrollX + ldy #$00 : jsr ApplyScroll + lda $a0 : and #$0f : cmp #$0f : bne + + stz $e0 : stz $e2 ; special case camera fix + lda #$1f : sta $e1 : sta $e3 + + + rts +} + +; Direction should be in $06, Shift Value (see above) in $02 and other info in $01 +; Sets $02, $04, $05, $ee, $045e, $045f and things related to Y coordinate +PrepScrollToInroomStairs: +{ + lda $01 : and #$30 : lsr #3 : tay + lda.w InroomStairsX,y : sta $04 + lda.w InroomStairsX+1,y : sta $05 + lda $06 : cmp #$ff : beq .south + lda.w InroomStairsY+1,y : bne + + inc $045f ; flag indicating special screen transition + dec $02 ; shift variables further + stz $aa + lda $a8 : and #%11111101 : sta $a8 + stz $0613 ; North scroll target + inc $0603 : inc $0607 + dec $0619 : dec $061b + + + lda.w InroomStairsY,y : !add #$20 : sta $20 + !sub #$38 : sta $045e + lda $01 : and #$40 : beq + + lda $20 : !add #$20 : sta $20 + stz $045f + + + dec $21 + %StonewallCheck($1b) + bra ++ + .south + lda.w InroomStairsY+1,y : beq + + inc $045f ; flag indicating special screen transition + inc $02 ; shift variables further + lda #$02 : sta $aa + lda $a8 : ora #%00000010 : sta $a8 + inc $0611 ; South scroll target + dec $0603 : dec $0607 + inc $0619 : inc $061b + + + lda.w InroomStairsY,y : !sub #$20 : sta $20 + !add #$38 : sta $045e + lda $01 : and #$40 : beq + + lda $20 : !sub #$20 : sta $20 + stz $045f + + + inc $21 + ++ + lda $01 : and #$04 : lsr #2 : sta $ee : bne + + stz $0476 + + rts +} ; Target pixel should be in A, other info in $01 ; Sets $04 $05 and $ee @@ -214,6 +289,7 @@ StraightStairsAdj: { stx $0464 : sty $012e ; what we wrote over lda.l DRMode : beq + + lda $045e : bne .toInroom jsr GetTileAttribute : tax lda $11 : cmp #$12 : beq .goingNorth lda $a2 : cmp #$51 : bne ++ @@ -234,6 +310,9 @@ StraightStairsAdj: pla : !add #$f6 : pha ++ pla : !add $0464 : sta $0464 + rtl + .toInroom + lda #$32 : sta $0464 : stz $045e + rtl } GetTileAttribute: @@ -283,11 +362,32 @@ DoorToStraight: rtl } +DoorToInroom: +{ + ldx $045e : bne .end + sta $0020, y ; what we wrote over + .end + ldx #$00 ; what we wrote over + rtl +} + +DoorToInroomEnd: +{ + ldy $045e : beq .vanilla + cmp $045e : bne .return + stz $045e ; clear + .return + rtl + .vanilla + cmp $02c034, x ; what we wrote over + rtl +} + StraightStairsTrapDoor: { lda $0464 : bne + ; reset function - phk : pea.w .jslrtsreturn-1 + .reset phk : pea.w .jslrtsreturn-1 pea.w $02802c jml $028c73 ; $10D71 .reset label of Bank02 .jslrtsreturn @@ -300,5 +400,15 @@ StraightStairsTrapDoor: inc $0468 : stz $068e : stz $0690 ++ rtl + jsl Dungeon_ApproachFixedColor ; what we wrote over - .end rtl + rtl +} + +InroomStairsTrapDoor: +{ + lda $0200 : cmp #$05 : beq .reset + lda $b0 : jml $008781 ; what we wrote over (essentially) + .reset + pla : pla : pla + jsl StraightStairsTrapDoor_reset + jml $028b15 ; just some RTS in bank 02 } \ No newline at end of file diff --git a/asm/overrides.asm b/asm/overrides.asm index b29c6bc1..d47d565f 100644 --- a/asm/overrides.asm +++ b/asm/overrides.asm @@ -37,6 +37,8 @@ OnFileLoadOverride: jsl OnFileLoad ; what I wrote over lda.l DRFlags : and #$80 : beq + ;flag is off lda $7ef086 : ora #$80 : sta $7ef086 + + lda.l DRFlags : and #$40 : beq + ;flag is off + lda $7ef036 : ora #$80 : sta $7ef036 + lda.l DRFlags : and #$02 : beq + lda $7ef353 : bne + lda #$01 : sta $7ef353 diff --git a/asm/scroll.asm b/asm/scroll.asm index 299b995a..8ee6e315 100644 --- a/asm/scroll.asm +++ b/asm/scroll.asm @@ -203,4 +203,18 @@ ApplyScroll: .end sta $00e2, y sta $00e0, y - stz $ab : sep #$30 : rts \ No newline at end of file + stz $ab : sep #$30 : rts + +QuadrantLoadOrderBeforeScroll: + lda $045f : beq .end + lda #$08 : sta $045c ; start with opposite quadrant row + .end + jsl $0091c4 ; what we overwrote + rtl + +QuadrantLoadOrderAfterScroll: + lda $045f : beq .end + stz $045c : stz $045f ; draw other row and clear flag + .end + jsl $0091c4 ; what we overwrote + rtl \ No newline at end of file diff --git a/asm/spiral.asm b/asm/spiral.asm index 2329c33b..0d13c4e7 100644 --- a/asm/spiral.asm +++ b/asm/spiral.asm @@ -2,9 +2,10 @@ RecordStairType: { pha lda.l DRMode : beq .norm lda $040c : cmp #$ff : beq .norm - lda $0e : sta $045e - cmp #$26 : beq .norm ; skipping in-floor staircases - pla : bra + + lda $0e + cmp #$25 : bcc ++ ; don't record straight staircases + sta $045e + ++ pla : bra + .norm pla : sta $a0 + lda $063d, x rtl @@ -15,8 +16,13 @@ SpiralWarp: { lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A! cmp #$5f : beq .gtg + cmp #$26 : beq .inroom .abort stz $045e : lda $a2 : and #$0f : rtl ; clear,run hijacked code and get out + .inroom + jsr InroomStairsWarp + lda $a2 : and #$0f ; this is the code we are hijacking + rtl .gtg phb : phk : plb : phx : phy ; push stuff @@ -70,6 +76,13 @@ SpiralWarp: { lda $01 : and #$20 : sta $07 ; zeroVtCam check ldy #$01 : jsr SetCamera + jsr StairCleanup + ply : plx : plb ; pull the stuff we pushed + lda $a2 : and #$0f ; this is the code we are hijacking + rtl +} + +StairCleanup: { stz $045e ; clear the staircase flag ; animated tiles fix @@ -81,9 +94,7 @@ SpiralWarp: { jsl DecompDungAnimatedTiles + stz $047a - ply : plx : plb ; pull the stuff we pushed - lda $a2 : and #$0f ; this is the code we are hijacking - rtl + rts } ;Sets the offset in A @@ -105,7 +116,7 @@ LookupSpiralOffset: { lda $a9 : ora $aa : and #$03 : beq .quad0 cmp #$01 : beq .quad1 cmp #$02 : beq .quad2 - cmp #$03 : beq .quad3 + bra .quad3 .quad0 inc $01 : lda $a2 cmp #$0c : beq .q0diff ;gt ent @@ -138,6 +149,103 @@ LookupSpiralOffset: { rts } +InroomStairsWarp: { + phb : phk : plb : phx : phy ; push stuff + ; find stairs by room and store index in X + lda $a0 : ldx #$07 + .loop + cmp.w InroomStairsRoom,x + beq .found + dex + bne .loop + .found + rep #$30 + txa : and #$00ff : asl : tay + lda.w InroomStairsTable,y : sta $00 + sep #$30 + sta $a0 + + ; set position and everything else based on target door type + txa : and #$01 : eor #$01 : sta $07 + ; should be the same as lda $0462 : and #$04 : lsr #2 : eor #$01 : sta $07 + lda $01 : and #$80 : beq .notEdge + lda $07 : sta $03 : beq + + lda $01 : jsr LoadSouthMidpoint : sta $22 : lda #$e0 + bra ++ + + + lda $01 : jsr LoadNorthMidpoint : sta $22 : lda #$1b + ++ + sta $20 + lda $01 : and #$20 : beq + + lda #$01 + + + sta $02 + stz $07 + lda $01 : and #$10 : lsr #4 + brl .layer + .notEdge + lda $01 : and #$03 : cmp #$03 : bne .normal + lda $01 : and #$30 : lsr #3 : tay + lda.w InroomStairsX,y : sta $22 + lda.w InroomStairsX+1,y : sta $02 + lda.w InroomStairsY+1,y : sta $03 + lda.w InroomStairsY,y + ldy $07 : beq + + !add #$07 + + + sta $20 + %StonewallCheck($1b) + inc $07 + lda $01 : and #$04 : lsr #2 + bra .layer + .normal + lda $01 : sta $fe ; trap door + lda $07 : sta $03 : beq + + lda #$e0 + ldy $a0 : cpy #$51 : bne ++ ; special fix for throne room + !sub #$18 + bra ++ + + + %StonewallCheck($43) + lda #$1b + ++ + sta $20 + inc $07 : stz $02 : lda #$78 : sta $22 + lda $01 : and #$03 : beq ++ + cmp #$02 : !bge + + lda #$f8 : sta $22 : stz $07 : bra ++ + + inc $02 + ++ + lda $01 : and #$04 : lsr #2 + + .layer + sta $ee + bne + + stz $0476 + + + + lda $02 : !sub $a9 + beq .skipXQuad + sta $06 : !add $a9 : sta $a9 + ldy #$00 : jsr ShiftQuadSimple + .skipXQuad + lda $aa : lsr : sta $06 : lda $03 : !sub $06 + beq .skipYQuad + sta $06 : asl : !add $aa : sta $aa + ldy #$01 : jsr ShiftQuadSimple + .skipYQuad + + ldy #$00 : jsr SetCamera ; horizontal camera + ldy #$01 : sty $07 : jsr SetCamera ; vertical camera + lda $20 : cmp #$e0 : bcc + + lda $e8 : bne + + lda #$10 : sta $e8 ; adjust vertical camera at bottom + + + jsr StairCleanup + ply : plx : plb ; pull the stuff we pushed + rts +} + ShiftQuadSimple: { lda.w CoordIndex,y : tax lda $20,x : beq .skip diff --git a/data/base2current.bps b/data/base2current.bps index 61323175..71800df8 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/data/sprites/official/4slink-armors.1.zspr b/data/sprites/official/4slink-armors.1.zspr deleted file mode 100644 index 7a944113..00000000 Binary files a/data/sprites/official/4slink-armors.1.zspr and /dev/null differ diff --git a/data/sprites/official/abigail.1.zspr b/data/sprites/official/abigail.1.zspr deleted file mode 100644 index 526990c5..00000000 Binary files a/data/sprites/official/abigail.1.zspr and /dev/null differ diff --git a/data/sprites/official/adol.1.zspr b/data/sprites/official/adol.1.zspr deleted file mode 100644 index da8210a9..00000000 Binary files a/data/sprites/official/adol.1.zspr and /dev/null differ diff --git a/data/sprites/official/aggretsuko.1.zspr b/data/sprites/official/aggretsuko.1.zspr deleted file mode 100644 index c23d9d83..00000000 Binary files a/data/sprites/official/aggretsuko.1.zspr and /dev/null differ diff --git a/data/sprites/official/alice.1.zspr b/data/sprites/official/alice.1.zspr deleted file mode 100644 index 4c673acd..00000000 Binary files a/data/sprites/official/alice.1.zspr and /dev/null differ diff --git a/data/sprites/official/angry-video-game-nerd.1.zspr b/data/sprites/official/angry-video-game-nerd.1.zspr deleted file mode 100644 index 79aee561..00000000 Binary files a/data/sprites/official/angry-video-game-nerd.1.zspr and /dev/null differ diff --git a/data/sprites/official/arcane.1.zspr b/data/sprites/official/arcane.1.zspr deleted file mode 100644 index b0fd4760..00000000 Binary files a/data/sprites/official/arcane.1.zspr and /dev/null differ diff --git a/data/sprites/official/ark-dorana.1.zspr b/data/sprites/official/ark-dorana.1.zspr deleted file mode 100644 index afd1c574..00000000 Binary files a/data/sprites/official/ark-dorana.1.zspr and /dev/null differ diff --git a/data/sprites/official/ark.1.zspr b/data/sprites/official/ark.1.zspr deleted file mode 100644 index 6ee7c09e..00000000 Binary files a/data/sprites/official/ark.1.zspr and /dev/null differ diff --git a/data/sprites/official/arrghus.2.zspr b/data/sprites/official/arrghus.2.zspr deleted file mode 100644 index 2064009d..00000000 Binary files a/data/sprites/official/arrghus.2.zspr and /dev/null differ diff --git a/data/sprites/official/astronaut.1.zspr b/data/sprites/official/astronaut.1.zspr deleted file mode 100644 index a4db3020..00000000 Binary files a/data/sprites/official/astronaut.1.zspr and /dev/null differ diff --git a/data/sprites/official/asuna.1.zspr b/data/sprites/official/asuna.1.zspr deleted file mode 100644 index f6f41545..00000000 Binary files a/data/sprites/official/asuna.1.zspr and /dev/null differ diff --git a/data/sprites/official/badeline.1.zspr b/data/sprites/official/badeline.1.zspr deleted file mode 100644 index b9fb1346..00000000 Binary files a/data/sprites/official/badeline.1.zspr and /dev/null differ diff --git a/data/sprites/official/bananas-in-pyjamas.1.zspr b/data/sprites/official/bananas-in-pyjamas.1.zspr deleted file mode 100644 index f75af2b2..00000000 Binary files a/data/sprites/official/bananas-in-pyjamas.1.zspr and /dev/null differ diff --git a/data/sprites/official/bandit.1.zspr b/data/sprites/official/bandit.1.zspr deleted file mode 100644 index 5b3288f8..00000000 Binary files a/data/sprites/official/bandit.1.zspr and /dev/null differ diff --git a/data/sprites/official/batman.1.zspr b/data/sprites/official/batman.1.zspr deleted file mode 100644 index a4a1e9c0..00000000 Binary files a/data/sprites/official/batman.1.zspr and /dev/null differ diff --git a/data/sprites/official/beau.1.zspr b/data/sprites/official/beau.1.zspr deleted file mode 100644 index 8d8d2079..00000000 Binary files a/data/sprites/official/beau.1.zspr and /dev/null differ diff --git a/data/sprites/official/bewp.1.zspr b/data/sprites/official/bewp.1.zspr deleted file mode 100644 index 265d2e1a..00000000 Binary files a/data/sprites/official/bewp.1.zspr and /dev/null differ diff --git a/data/sprites/official/bigkey.1.zspr b/data/sprites/official/bigkey.1.zspr deleted file mode 100644 index eab4854e..00000000 Binary files a/data/sprites/official/bigkey.1.zspr and /dev/null differ diff --git a/data/sprites/official/birb.1.zspr b/data/sprites/official/birb.1.zspr deleted file mode 100644 index d6d86bb6..00000000 Binary files a/data/sprites/official/birb.1.zspr and /dev/null differ diff --git a/data/sprites/official/birdo.1.zspr b/data/sprites/official/birdo.1.zspr deleted file mode 100644 index 54c49747..00000000 Binary files a/data/sprites/official/birdo.1.zspr and /dev/null differ diff --git a/data/sprites/official/blackmage.1.zspr b/data/sprites/official/blackmage.1.zspr deleted file mode 100644 index d9b56288..00000000 Binary files a/data/sprites/official/blackmage.1.zspr and /dev/null differ diff --git a/data/sprites/official/blacksmithlink.1.zspr b/data/sprites/official/blacksmithlink.1.zspr deleted file mode 100644 index e9aeb31a..00000000 Binary files a/data/sprites/official/blacksmithlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/blazer.1.zspr b/data/sprites/official/blazer.1.zspr deleted file mode 100644 index 9a15c25c..00000000 Binary files a/data/sprites/official/blazer.1.zspr and /dev/null differ diff --git a/data/sprites/official/blossom.1.zspr b/data/sprites/official/blossom.1.zspr deleted file mode 100644 index 57f4918c..00000000 Binary files a/data/sprites/official/blossom.1.zspr and /dev/null differ diff --git a/data/sprites/official/bobross.1.zspr b/data/sprites/official/bobross.1.zspr deleted file mode 100644 index eaa9811b..00000000 Binary files a/data/sprites/official/bobross.1.zspr and /dev/null differ diff --git a/data/sprites/official/boco.1.zspr b/data/sprites/official/boco.1.zspr deleted file mode 100644 index 21825520..00000000 Binary files a/data/sprites/official/boco.1.zspr and /dev/null differ diff --git a/data/sprites/official/boo-two.1.zspr b/data/sprites/official/boo-two.1.zspr deleted file mode 100644 index a5c5463c..00000000 Binary files a/data/sprites/official/boo-two.1.zspr and /dev/null differ diff --git a/data/sprites/official/boo.2.zspr b/data/sprites/official/boo.2.zspr deleted file mode 100644 index 24c74bde..00000000 Binary files a/data/sprites/official/boo.2.zspr and /dev/null differ diff --git a/data/sprites/official/bottle_o_goo.1.zspr b/data/sprites/official/bottle_o_goo.1.zspr deleted file mode 100644 index 28ca1f9b..00000000 Binary files a/data/sprites/official/bottle_o_goo.1.zspr and /dev/null differ diff --git a/data/sprites/official/botw-link.1.zspr b/data/sprites/official/botw-link.1.zspr deleted file mode 100644 index 1e14eff1..00000000 Binary files a/data/sprites/official/botw-link.1.zspr and /dev/null differ diff --git a/data/sprites/official/botw-zelda.1.zspr b/data/sprites/official/botw-zelda.1.zspr deleted file mode 100644 index 39f4a893..00000000 Binary files a/data/sprites/official/botw-zelda.1.zspr and /dev/null differ diff --git a/data/sprites/official/bowser.1.zspr b/data/sprites/official/bowser.1.zspr deleted file mode 100644 index 1cc256d8..00000000 Binary files a/data/sprites/official/bowser.1.zspr and /dev/null differ diff --git a/data/sprites/official/bowsette-red.1.zspr b/data/sprites/official/bowsette-red.1.zspr deleted file mode 100644 index d4bd4346..00000000 Binary files a/data/sprites/official/bowsette-red.1.zspr and /dev/null differ diff --git a/data/sprites/official/bowsette.1.zspr b/data/sprites/official/bowsette.1.zspr deleted file mode 100644 index 017414bc..00000000 Binary files a/data/sprites/official/bowsette.1.zspr and /dev/null differ diff --git a/data/sprites/official/branch.1.zspr b/data/sprites/official/branch.1.zspr deleted file mode 100644 index b7926418..00000000 Binary files a/data/sprites/official/branch.1.zspr and /dev/null differ diff --git a/data/sprites/official/brian.1.zspr b/data/sprites/official/brian.1.zspr deleted file mode 100644 index 013a2207..00000000 Binary files a/data/sprites/official/brian.1.zspr and /dev/null differ diff --git a/data/sprites/official/broccoli.1.zspr b/data/sprites/official/broccoli.1.zspr deleted file mode 100644 index e335df01..00000000 Binary files a/data/sprites/official/broccoli.1.zspr and /dev/null differ diff --git a/data/sprites/official/bronzor.1.zspr b/data/sprites/official/bronzor.1.zspr deleted file mode 100644 index d1afd117..00000000 Binary files a/data/sprites/official/bronzor.1.zspr and /dev/null differ diff --git a/data/sprites/official/bsboy.1.zspr b/data/sprites/official/bsboy.1.zspr deleted file mode 100644 index 7d00be74..00000000 Binary files a/data/sprites/official/bsboy.1.zspr and /dev/null differ diff --git a/data/sprites/official/bsgirl.1.zspr b/data/sprites/official/bsgirl.1.zspr deleted file mode 100644 index 82923751..00000000 Binary files a/data/sprites/official/bsgirl.1.zspr and /dev/null differ diff --git a/data/sprites/official/bubbles.1.zspr b/data/sprites/official/bubbles.1.zspr deleted file mode 100644 index bbba3b75..00000000 Binary files a/data/sprites/official/bubbles.1.zspr and /dev/null differ diff --git a/data/sprites/official/bullet_bill.1.zspr b/data/sprites/official/bullet_bill.1.zspr deleted file mode 100644 index 5b561b9e..00000000 Binary files a/data/sprites/official/bullet_bill.1.zspr and /dev/null differ diff --git a/data/sprites/official/buttercup.1.zspr b/data/sprites/official/buttercup.1.zspr deleted file mode 100644 index bd066c27..00000000 Binary files a/data/sprites/official/buttercup.1.zspr and /dev/null differ diff --git a/data/sprites/official/cactuar.1.zspr b/data/sprites/official/cactuar.1.zspr deleted file mode 100644 index 51c32893..00000000 Binary files a/data/sprites/official/cactuar.1.zspr and /dev/null differ diff --git a/data/sprites/official/cadence.1.zspr b/data/sprites/official/cadence.1.zspr deleted file mode 100644 index 05f174f7..00000000 Binary files a/data/sprites/official/cadence.1.zspr and /dev/null differ diff --git a/data/sprites/official/carlsagan42.1.zspr b/data/sprites/official/carlsagan42.1.zspr deleted file mode 100644 index 2632cb6f..00000000 Binary files a/data/sprites/official/carlsagan42.1.zspr and /dev/null differ diff --git a/data/sprites/official/casual-zelda.1.zspr b/data/sprites/official/casual-zelda.1.zspr deleted file mode 100644 index 80257f11..00000000 Binary files a/data/sprites/official/casual-zelda.1.zspr and /dev/null differ diff --git a/data/sprites/official/cat.3.zspr b/data/sprites/official/cat.3.zspr deleted file mode 100644 index 69946d73..00000000 Binary files a/data/sprites/official/cat.3.zspr and /dev/null differ diff --git a/data/sprites/official/catboo.1.zspr b/data/sprites/official/catboo.1.zspr deleted file mode 100644 index 45a4fa81..00000000 Binary files a/data/sprites/official/catboo.1.zspr and /dev/null differ diff --git a/data/sprites/official/cdilink.1.zspr b/data/sprites/official/cdilink.1.zspr deleted file mode 100644 index 3236f799..00000000 Binary files a/data/sprites/official/cdilink.1.zspr and /dev/null differ diff --git a/data/sprites/official/celes.1.zspr b/data/sprites/official/celes.1.zspr deleted file mode 100644 index ac0c1226..00000000 Binary files a/data/sprites/official/celes.1.zspr and /dev/null differ diff --git a/data/sprites/official/charizard.1.zspr b/data/sprites/official/charizard.1.zspr deleted file mode 100644 index babed511..00000000 Binary files a/data/sprites/official/charizard.1.zspr and /dev/null differ diff --git a/data/sprites/official/cheepcheep.1.zspr b/data/sprites/official/cheepcheep.1.zspr deleted file mode 100644 index a49545f2..00000000 Binary files a/data/sprites/official/cheepcheep.1.zspr and /dev/null differ diff --git a/data/sprites/official/chibity.1.zspr b/data/sprites/official/chibity.1.zspr deleted file mode 100644 index 949dbe2e..00000000 Binary files a/data/sprites/official/chibity.1.zspr and /dev/null differ diff --git a/data/sprites/official/chrizzz.1.zspr b/data/sprites/official/chrizzz.1.zspr deleted file mode 100644 index 337d5e5d..00000000 Binary files a/data/sprites/official/chrizzz.1.zspr and /dev/null differ diff --git a/data/sprites/official/cirno.1.zspr b/data/sprites/official/cirno.1.zspr deleted file mode 100644 index 75de8ab6..00000000 Binary files a/data/sprites/official/cirno.1.zspr and /dev/null differ diff --git a/data/sprites/official/clifford.1.zspr b/data/sprites/official/clifford.1.zspr deleted file mode 100644 index 73f848c1..00000000 Binary files a/data/sprites/official/clifford.1.zspr and /dev/null differ diff --git a/data/sprites/official/clyde.1.zspr b/data/sprites/official/clyde.1.zspr deleted file mode 100644 index b590a2ef..00000000 Binary files a/data/sprites/official/clyde.1.zspr and /dev/null differ diff --git a/data/sprites/official/conker.1.zspr b/data/sprites/official/conker.1.zspr deleted file mode 100644 index 121d5233..00000000 Binary files a/data/sprites/official/conker.1.zspr and /dev/null differ diff --git a/data/sprites/official/cornelius.1.zspr b/data/sprites/official/cornelius.1.zspr deleted file mode 100644 index 4c58f356..00000000 Binary files a/data/sprites/official/cornelius.1.zspr and /dev/null differ diff --git a/data/sprites/official/corona.1.zspr b/data/sprites/official/corona.1.zspr deleted file mode 100644 index 2ed39a78..00000000 Binary files a/data/sprites/official/corona.1.zspr and /dev/null differ diff --git a/data/sprites/official/crewmate.1.zspr b/data/sprites/official/crewmate.1.zspr deleted file mode 100644 index f2ce441d..00000000 Binary files a/data/sprites/official/crewmate.1.zspr and /dev/null differ diff --git a/data/sprites/official/cucco.1.zspr b/data/sprites/official/cucco.1.zspr deleted file mode 100644 index f237de4a..00000000 Binary files a/data/sprites/official/cucco.1.zspr and /dev/null differ diff --git a/data/sprites/official/cursor.1.zspr b/data/sprites/official/cursor.1.zspr deleted file mode 100644 index 45bc9739..00000000 Binary files a/data/sprites/official/cursor.1.zspr and /dev/null differ diff --git a/data/sprites/official/d_owls.2.zspr b/data/sprites/official/d_owls.2.zspr deleted file mode 100644 index a49080bb..00000000 Binary files a/data/sprites/official/d_owls.2.zspr and /dev/null differ diff --git a/data/sprites/official/dark-panda.1.zspr b/data/sprites/official/dark-panda.1.zspr deleted file mode 100644 index 1b39b747..00000000 Binary files a/data/sprites/official/dark-panda.1.zspr and /dev/null differ diff --git a/data/sprites/official/darkboy.1.zspr b/data/sprites/official/darkboy.1.zspr deleted file mode 100644 index de55ebbe..00000000 Binary files a/data/sprites/official/darkboy.1.zspr and /dev/null differ diff --git a/data/sprites/official/darkgirl.1.zspr b/data/sprites/official/darkgirl.1.zspr deleted file mode 100644 index 8fd848fd..00000000 Binary files a/data/sprites/official/darkgirl.1.zspr and /dev/null differ diff --git a/data/sprites/official/darklink-tunic.1.zspr b/data/sprites/official/darklink-tunic.1.zspr deleted file mode 100644 index fe417308..00000000 Binary files a/data/sprites/official/darklink-tunic.1.zspr and /dev/null differ diff --git a/data/sprites/official/darklink.1.zspr b/data/sprites/official/darklink.1.zspr deleted file mode 100644 index b0d9a95f..00000000 Binary files a/data/sprites/official/darklink.1.zspr and /dev/null differ diff --git a/data/sprites/official/darkswatchy.1.zspr b/data/sprites/official/darkswatchy.1.zspr deleted file mode 100644 index 88677425..00000000 Binary files a/data/sprites/official/darkswatchy.1.zspr and /dev/null differ diff --git a/data/sprites/official/darkzelda.1.zspr b/data/sprites/official/darkzelda.1.zspr deleted file mode 100644 index 519c278a..00000000 Binary files a/data/sprites/official/darkzelda.1.zspr and /dev/null differ diff --git a/data/sprites/official/darkzora.2.zspr b/data/sprites/official/darkzora.2.zspr deleted file mode 100644 index fbb15c69..00000000 Binary files a/data/sprites/official/darkzora.2.zspr and /dev/null differ diff --git a/data/sprites/official/deadpool-mythic.1.zspr b/data/sprites/official/deadpool-mythic.1.zspr deleted file mode 100644 index abcda926..00000000 Binary files a/data/sprites/official/deadpool-mythic.1.zspr and /dev/null differ diff --git a/data/sprites/official/deadpool.1.zspr b/data/sprites/official/deadpool.1.zspr deleted file mode 100644 index 3d2e87f7..00000000 Binary files a/data/sprites/official/deadpool.1.zspr and /dev/null differ diff --git a/data/sprites/official/deadrock.1.zspr b/data/sprites/official/deadrock.1.zspr deleted file mode 100644 index cc28cd79..00000000 Binary files a/data/sprites/official/deadrock.1.zspr and /dev/null differ diff --git a/data/sprites/official/decidueye.1.zspr b/data/sprites/official/decidueye.1.zspr deleted file mode 100644 index 1c769e62..00000000 Binary files a/data/sprites/official/decidueye.1.zspr and /dev/null differ diff --git a/data/sprites/official/dekar.1.zspr b/data/sprites/official/dekar.1.zspr deleted file mode 100644 index 203abccd..00000000 Binary files a/data/sprites/official/dekar.1.zspr and /dev/null differ diff --git a/data/sprites/official/demonlink.1.zspr b/data/sprites/official/demonlink.1.zspr deleted file mode 100644 index 2daf7359..00000000 Binary files a/data/sprites/official/demonlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/dragonite.2.zspr b/data/sprites/official/dragonite.2.zspr deleted file mode 100644 index 37d95ad0..00000000 Binary files a/data/sprites/official/dragonite.2.zspr and /dev/null differ diff --git a/data/sprites/official/drake.1.zspr b/data/sprites/official/drake.1.zspr deleted file mode 100644 index 1be94a75..00000000 Binary files a/data/sprites/official/drake.1.zspr and /dev/null differ diff --git a/data/sprites/official/eggplant.1.zspr b/data/sprites/official/eggplant.1.zspr deleted file mode 100644 index c33c2008..00000000 Binary files a/data/sprites/official/eggplant.1.zspr and /dev/null differ diff --git a/data/sprites/official/emosaru.1.zspr b/data/sprites/official/emosaru.1.zspr deleted file mode 100644 index a636dad9..00000000 Binary files a/data/sprites/official/emosaru.1.zspr and /dev/null differ diff --git a/data/sprites/official/ezlo.1.zspr b/data/sprites/official/ezlo.1.zspr deleted file mode 100644 index 54596847..00000000 Binary files a/data/sprites/official/ezlo.1.zspr and /dev/null differ diff --git a/data/sprites/official/fierce-deity-link.2.zspr b/data/sprites/official/fierce-deity-link.2.zspr deleted file mode 100644 index 0700bcac..00000000 Binary files a/data/sprites/official/fierce-deity-link.2.zspr and /dev/null differ diff --git a/data/sprites/official/finn.3.zspr b/data/sprites/official/finn.3.zspr deleted file mode 100644 index 265b197c..00000000 Binary files a/data/sprites/official/finn.3.zspr and /dev/null differ diff --git a/data/sprites/official/finny_bear.1.zspr b/data/sprites/official/finny_bear.1.zspr deleted file mode 100644 index 9c3a530b..00000000 Binary files a/data/sprites/official/finny_bear.1.zspr and /dev/null differ diff --git a/data/sprites/official/fish_floodgate.1.zspr b/data/sprites/official/fish_floodgate.1.zspr deleted file mode 100644 index 86684e7d..00000000 Binary files a/data/sprites/official/fish_floodgate.1.zspr and /dev/null differ diff --git a/data/sprites/official/flavor_guy.1.zspr b/data/sprites/official/flavor_guy.1.zspr deleted file mode 100644 index 5e1df365..00000000 Binary files a/data/sprites/official/flavor_guy.1.zspr and /dev/null differ diff --git a/data/sprites/official/foxlink.1.zspr b/data/sprites/official/foxlink.1.zspr deleted file mode 100644 index d6eaf433..00000000 Binary files a/data/sprites/official/foxlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/freya.1.zspr b/data/sprites/official/freya.1.zspr deleted file mode 100644 index b43338d5..00000000 Binary files a/data/sprites/official/freya.1.zspr and /dev/null differ diff --git a/data/sprites/official/frisk.1.zspr b/data/sprites/official/frisk.1.zspr deleted file mode 100644 index d521cae3..00000000 Binary files a/data/sprites/official/frisk.1.zspr and /dev/null differ diff --git a/data/sprites/official/froglink.3.zspr b/data/sprites/official/froglink.3.zspr deleted file mode 100644 index f5c46d82..00000000 Binary files a/data/sprites/official/froglink.3.zspr and /dev/null differ diff --git a/data/sprites/official/fujin.2.zspr b/data/sprites/official/fujin.2.zspr deleted file mode 100644 index 9254ff7b..00000000 Binary files a/data/sprites/official/fujin.2.zspr and /dev/null differ diff --git a/data/sprites/official/future_trunks.1.zspr b/data/sprites/official/future_trunks.1.zspr deleted file mode 100644 index 456e64c7..00000000 Binary files a/data/sprites/official/future_trunks.1.zspr and /dev/null differ diff --git a/data/sprites/official/gamer.1.zspr b/data/sprites/official/gamer.1.zspr deleted file mode 100644 index 9f78d894..00000000 Binary files a/data/sprites/official/gamer.1.zspr and /dev/null differ diff --git a/data/sprites/official/ganon.1.zspr b/data/sprites/official/ganon.1.zspr deleted file mode 100644 index a6adda43..00000000 Binary files a/data/sprites/official/ganon.1.zspr and /dev/null differ diff --git a/data/sprites/official/ganondorf.1.zspr b/data/sprites/official/ganondorf.1.zspr deleted file mode 100644 index 5bb6f548..00000000 Binary files a/data/sprites/official/ganondorf.1.zspr and /dev/null differ diff --git a/data/sprites/official/garfield.2.zspr b/data/sprites/official/garfield.2.zspr deleted file mode 100644 index 6ca890e8..00000000 Binary files a/data/sprites/official/garfield.2.zspr and /dev/null differ diff --git a/data/sprites/official/garnet.1.zspr b/data/sprites/official/garnet.1.zspr deleted file mode 100644 index 858497c7..00000000 Binary files a/data/sprites/official/garnet.1.zspr and /dev/null differ diff --git a/data/sprites/official/garomaster.1.zspr b/data/sprites/official/garomaster.1.zspr deleted file mode 100644 index 65b9959d..00000000 Binary files a/data/sprites/official/garomaster.1.zspr and /dev/null differ diff --git a/data/sprites/official/gbc-link.1.zspr b/data/sprites/official/gbc-link.1.zspr deleted file mode 100644 index e98a6d08..00000000 Binary files a/data/sprites/official/gbc-link.1.zspr and /dev/null differ diff --git a/data/sprites/official/geno.1.zspr b/data/sprites/official/geno.1.zspr deleted file mode 100644 index 3d747a2a..00000000 Binary files a/data/sprites/official/geno.1.zspr and /dev/null differ diff --git a/data/sprites/official/gliitchwiitch.1.zspr b/data/sprites/official/gliitchwiitch.1.zspr deleted file mode 100644 index 0f618df0..00000000 Binary files a/data/sprites/official/gliitchwiitch.1.zspr and /dev/null differ diff --git a/data/sprites/official/gobli.1.zspr b/data/sprites/official/gobli.1.zspr deleted file mode 100644 index 51dd1192..00000000 Binary files a/data/sprites/official/gobli.1.zspr and /dev/null differ diff --git a/data/sprites/official/goomba.1.zspr b/data/sprites/official/goomba.1.zspr deleted file mode 100644 index 0438682f..00000000 Binary files a/data/sprites/official/goomba.1.zspr and /dev/null differ diff --git a/data/sprites/official/goose.1.zspr b/data/sprites/official/goose.1.zspr deleted file mode 100644 index d2ffb5ba..00000000 Binary files a/data/sprites/official/goose.1.zspr and /dev/null differ diff --git a/data/sprites/official/grandpoobear.2.zspr b/data/sprites/official/grandpoobear.2.zspr deleted file mode 100644 index 72663680..00000000 Binary files a/data/sprites/official/grandpoobear.2.zspr and /dev/null differ diff --git a/data/sprites/official/gretis.1.zspr b/data/sprites/official/gretis.1.zspr deleted file mode 100644 index 87607a17..00000000 Binary files a/data/sprites/official/gretis.1.zspr and /dev/null differ diff --git a/data/sprites/official/grunclestan.1.zspr b/data/sprites/official/grunclestan.1.zspr deleted file mode 100644 index cf371839..00000000 Binary files a/data/sprites/official/grunclestan.1.zspr and /dev/null differ diff --git a/data/sprites/official/guiz.1.zspr b/data/sprites/official/guiz.1.zspr deleted file mode 100644 index 995c08ad..00000000 Binary files a/data/sprites/official/guiz.1.zspr and /dev/null differ diff --git a/data/sprites/official/hanna.1.zspr b/data/sprites/official/hanna.1.zspr deleted file mode 100644 index 92ce372e..00000000 Binary files a/data/sprites/official/hanna.1.zspr and /dev/null differ diff --git a/data/sprites/official/hardhat_beetle.1.zspr b/data/sprites/official/hardhat_beetle.1.zspr deleted file mode 100644 index 80b63af1..00000000 Binary files a/data/sprites/official/hardhat_beetle.1.zspr and /dev/null differ diff --git a/data/sprites/official/hat-kid.1.zspr b/data/sprites/official/hat-kid.1.zspr deleted file mode 100644 index d0341060..00000000 Binary files a/data/sprites/official/hat-kid.1.zspr and /dev/null differ diff --git a/data/sprites/official/headlesslink.1.zspr b/data/sprites/official/headlesslink.1.zspr deleted file mode 100644 index 8a9b3ce4..00000000 Binary files a/data/sprites/official/headlesslink.1.zspr and /dev/null differ diff --git a/data/sprites/official/hello_kitty.1.zspr b/data/sprites/official/hello_kitty.1.zspr deleted file mode 100644 index a2f5df06..00000000 Binary files a/data/sprites/official/hello_kitty.1.zspr and /dev/null differ diff --git a/data/sprites/official/hidari.1.zspr b/data/sprites/official/hidari.1.zspr deleted file mode 100644 index 54a4d0da..00000000 Binary files a/data/sprites/official/hidari.1.zspr and /dev/null differ diff --git a/data/sprites/official/hint_tile.1.zspr b/data/sprites/official/hint_tile.1.zspr deleted file mode 100644 index 9cfd7e90..00000000 Binary files a/data/sprites/official/hint_tile.1.zspr and /dev/null differ diff --git a/data/sprites/official/hoarder-bush.1.zspr b/data/sprites/official/hoarder-bush.1.zspr deleted file mode 100644 index d2adb227..00000000 Binary files a/data/sprites/official/hoarder-bush.1.zspr and /dev/null differ diff --git a/data/sprites/official/hoarder-pot.1.zspr b/data/sprites/official/hoarder-pot.1.zspr deleted file mode 100644 index 717e4199..00000000 Binary files a/data/sprites/official/hoarder-pot.1.zspr and /dev/null differ diff --git a/data/sprites/official/hoarder-rock.1.zspr b/data/sprites/official/hoarder-rock.1.zspr deleted file mode 100644 index a93fd1c4..00000000 Binary files a/data/sprites/official/hoarder-rock.1.zspr and /dev/null differ diff --git a/data/sprites/official/hollow-knight.1.zspr b/data/sprites/official/hollow-knight.1.zspr deleted file mode 100644 index 31d8ee3d..00000000 Binary files a/data/sprites/official/hollow-knight.1.zspr and /dev/null differ diff --git a/data/sprites/official/homer.1.zspr b/data/sprites/official/homer.1.zspr deleted file mode 100644 index ee8b5f5f..00000000 Binary files a/data/sprites/official/homer.1.zspr and /dev/null differ diff --git a/data/sprites/official/hotdog.1.zspr b/data/sprites/official/hotdog.1.zspr deleted file mode 100644 index 4ed5e636..00000000 Binary files a/data/sprites/official/hotdog.1.zspr and /dev/null differ diff --git a/data/sprites/official/hyruleknight.1.zspr b/data/sprites/official/hyruleknight.1.zspr deleted file mode 100644 index a8815bc3..00000000 Binary files a/data/sprites/official/hyruleknight.1.zspr and /dev/null differ diff --git a/data/sprites/official/ibazly.1.zspr b/data/sprites/official/ibazly.1.zspr deleted file mode 100644 index 01114c9e..00000000 Binary files a/data/sprites/official/ibazly.1.zspr and /dev/null differ diff --git a/data/sprites/official/ignignokt.2.zspr b/data/sprites/official/ignignokt.2.zspr deleted file mode 100644 index f06d07cc..00000000 Binary files a/data/sprites/official/ignignokt.2.zspr and /dev/null differ diff --git a/data/sprites/official/informant_woman.1.zspr b/data/sprites/official/informant_woman.1.zspr deleted file mode 100644 index 6465a0e9..00000000 Binary files a/data/sprites/official/informant_woman.1.zspr and /dev/null differ diff --git a/data/sprites/official/inkling.1.zspr b/data/sprites/official/inkling.1.zspr deleted file mode 100644 index 6b39e4a7..00000000 Binary files a/data/sprites/official/inkling.1.zspr and /dev/null differ diff --git a/data/sprites/official/invisibleman.1.zspr b/data/sprites/official/invisibleman.1.zspr deleted file mode 100644 index 7993c500..00000000 Binary files a/data/sprites/official/invisibleman.1.zspr and /dev/null differ diff --git a/data/sprites/official/jack-frost.1.zspr b/data/sprites/official/jack-frost.1.zspr deleted file mode 100644 index 12dd417a..00000000 Binary files a/data/sprites/official/jack-frost.1.zspr and /dev/null differ diff --git a/data/sprites/official/jason_frudnick.1.zspr b/data/sprites/official/jason_frudnick.1.zspr deleted file mode 100644 index 2411759c..00000000 Binary files a/data/sprites/official/jason_frudnick.1.zspr and /dev/null differ diff --git a/data/sprites/official/jasp.1.zspr b/data/sprites/official/jasp.1.zspr deleted file mode 100644 index 6dc74496..00000000 Binary files a/data/sprites/official/jasp.1.zspr and /dev/null differ diff --git a/data/sprites/official/jogurt.1.zspr b/data/sprites/official/jogurt.1.zspr deleted file mode 100644 index b229060c..00000000 Binary files a/data/sprites/official/jogurt.1.zspr and /dev/null differ diff --git a/data/sprites/official/katsura.1.zspr b/data/sprites/official/katsura.1.zspr deleted file mode 100644 index 422a0faf..00000000 Binary files a/data/sprites/official/katsura.1.zspr and /dev/null differ diff --git a/data/sprites/official/kecleon.1.zspr b/data/sprites/official/kecleon.1.zspr deleted file mode 100644 index 5e1786ba..00000000 Binary files a/data/sprites/official/kecleon.1.zspr and /dev/null differ diff --git a/data/sprites/official/kenny_mccormick.1.zspr b/data/sprites/official/kenny_mccormick.1.zspr deleted file mode 100644 index c66a74a5..00000000 Binary files a/data/sprites/official/kenny_mccormick.1.zspr and /dev/null differ diff --git a/data/sprites/official/ketchup.1.zspr b/data/sprites/official/ketchup.1.zspr deleted file mode 100644 index 9dbb326c..00000000 Binary files a/data/sprites/official/ketchup.1.zspr and /dev/null differ diff --git a/data/sprites/official/kholdstare.1.zspr b/data/sprites/official/kholdstare.1.zspr deleted file mode 100644 index 393a491d..00000000 Binary files a/data/sprites/official/kholdstare.1.zspr and /dev/null differ diff --git a/data/sprites/official/king_gothalion.1.zspr b/data/sprites/official/king_gothalion.1.zspr deleted file mode 100644 index 65c73f04..00000000 Binary files a/data/sprites/official/king_gothalion.1.zspr and /dev/null differ diff --git a/data/sprites/official/king_graham.1.zspr b/data/sprites/official/king_graham.1.zspr deleted file mode 100644 index 28b75cf1..00000000 Binary files a/data/sprites/official/king_graham.1.zspr and /dev/null differ diff --git a/data/sprites/official/kirby-meta.1.zspr b/data/sprites/official/kirby-meta.1.zspr deleted file mode 100644 index 9cb132b3..00000000 Binary files a/data/sprites/official/kirby-meta.1.zspr and /dev/null differ diff --git a/data/sprites/official/kore8.1.zspr b/data/sprites/official/kore8.1.zspr deleted file mode 100644 index a1db104a..00000000 Binary files a/data/sprites/official/kore8.1.zspr and /dev/null differ diff --git a/data/sprites/official/korok.1.zspr b/data/sprites/official/korok.1.zspr deleted file mode 100644 index 3045b95b..00000000 Binary files a/data/sprites/official/korok.1.zspr and /dev/null differ diff --git a/data/sprites/official/lakitu.1.zspr b/data/sprites/official/lakitu.1.zspr deleted file mode 100644 index 24d0f12e..00000000 Binary files a/data/sprites/official/lakitu.1.zspr and /dev/null differ diff --git a/data/sprites/official/lapras.1.zspr b/data/sprites/official/lapras.1.zspr deleted file mode 100644 index bcec01b2..00000000 Binary files a/data/sprites/official/lapras.1.zspr and /dev/null differ diff --git a/data/sprites/official/lest.1.zspr b/data/sprites/official/lest.1.zspr deleted file mode 100644 index 99764924..00000000 Binary files a/data/sprites/official/lest.1.zspr and /dev/null differ diff --git a/data/sprites/official/lily.1.zspr b/data/sprites/official/lily.1.zspr deleted file mode 100644 index 5cb5d2aa..00000000 Binary files a/data/sprites/official/lily.1.zspr and /dev/null differ diff --git a/data/sprites/official/linja.1.zspr b/data/sprites/official/linja.1.zspr deleted file mode 100644 index 414efaf7..00000000 Binary files a/data/sprites/official/linja.1.zspr and /dev/null differ diff --git a/data/sprites/official/link-redrawn.1.zspr b/data/sprites/official/link-redrawn.1.zspr deleted file mode 100644 index 1cbb7501..00000000 Binary files a/data/sprites/official/link-redrawn.1.zspr and /dev/null differ diff --git a/data/sprites/official/linkhatcolor.1.zspr b/data/sprites/official/linkhatcolor.1.zspr deleted file mode 100644 index af53898d..00000000 Binary files a/data/sprites/official/linkhatcolor.1.zspr and /dev/null differ diff --git a/data/sprites/official/linktuniccolor.1.zspr b/data/sprites/official/linktuniccolor.1.zspr deleted file mode 100644 index 305a9f8f..00000000 Binary files a/data/sprites/official/linktuniccolor.1.zspr and /dev/null differ diff --git a/data/sprites/official/little-hylian.1.zspr b/data/sprites/official/little-hylian.1.zspr deleted file mode 100644 index fbee749c..00000000 Binary files a/data/sprites/official/little-hylian.1.zspr and /dev/null differ diff --git a/data/sprites/official/littlepony.1.zspr b/data/sprites/official/littlepony.1.zspr deleted file mode 100644 index 0ed4b1b1..00000000 Binary files a/data/sprites/official/littlepony.1.zspr and /dev/null differ diff --git a/data/sprites/official/locke.1.zspr b/data/sprites/official/locke.1.zspr deleted file mode 100644 index c2273791..00000000 Binary files a/data/sprites/official/locke.1.zspr and /dev/null differ diff --git a/data/sprites/official/locke_merchant.1.zspr b/data/sprites/official/locke_merchant.1.zspr deleted file mode 100644 index bfd87c7d..00000000 Binary files a/data/sprites/official/locke_merchant.1.zspr and /dev/null differ diff --git a/data/sprites/official/lucario.1.zspr b/data/sprites/official/lucario.1.zspr deleted file mode 100644 index 44ce395e..00000000 Binary files a/data/sprites/official/lucario.1.zspr and /dev/null differ diff --git a/data/sprites/official/luffy.1.zspr b/data/sprites/official/luffy.1.zspr deleted file mode 100644 index 0661577b..00000000 Binary files a/data/sprites/official/luffy.1.zspr and /dev/null differ diff --git a/data/sprites/official/luigi.1.zspr b/data/sprites/official/luigi.1.zspr deleted file mode 100644 index 1a1dc552..00000000 Binary files a/data/sprites/official/luigi.1.zspr and /dev/null differ diff --git a/data/sprites/official/luna-maindo.1.zspr b/data/sprites/official/luna-maindo.1.zspr deleted file mode 100644 index 5a8acdbf..00000000 Binary files a/data/sprites/official/luna-maindo.1.zspr and /dev/null differ diff --git a/data/sprites/official/madeline.1.zspr b/data/sprites/official/madeline.1.zspr deleted file mode 100644 index 8256e6a3..00000000 Binary files a/data/sprites/official/madeline.1.zspr and /dev/null differ diff --git a/data/sprites/official/magus.1.zspr b/data/sprites/official/magus.1.zspr deleted file mode 100644 index 171980ef..00000000 Binary files a/data/sprites/official/magus.1.zspr and /dev/null differ diff --git a/data/sprites/official/maiden.1.zspr b/data/sprites/official/maiden.1.zspr deleted file mode 100644 index e0297901..00000000 Binary files a/data/sprites/official/maiden.1.zspr and /dev/null differ diff --git a/data/sprites/official/mallow-cat.1.zspr b/data/sprites/official/mallow-cat.1.zspr deleted file mode 100644 index 395684b2..00000000 Binary files a/data/sprites/official/mallow-cat.1.zspr and /dev/null differ diff --git a/data/sprites/official/mangalink.1.zspr b/data/sprites/official/mangalink.1.zspr deleted file mode 100644 index adb57b99..00000000 Binary files a/data/sprites/official/mangalink.1.zspr and /dev/null differ diff --git a/data/sprites/official/maplequeen.2.zspr b/data/sprites/official/maplequeen.2.zspr deleted file mode 100644 index 35b7deec..00000000 Binary files a/data/sprites/official/maplequeen.2.zspr and /dev/null differ diff --git a/data/sprites/official/marin.2.zspr b/data/sprites/official/marin.2.zspr deleted file mode 100644 index 72a06ecf..00000000 Binary files a/data/sprites/official/marin.2.zspr and /dev/null differ diff --git a/data/sprites/official/mario-classic.2.zspr b/data/sprites/official/mario-classic.2.zspr deleted file mode 100644 index 6443e327..00000000 Binary files a/data/sprites/official/mario-classic.2.zspr and /dev/null differ diff --git a/data/sprites/official/mario_tanooki.1.zspr b/data/sprites/official/mario_tanooki.1.zspr deleted file mode 100644 index 255350dd..00000000 Binary files a/data/sprites/official/mario_tanooki.1.zspr and /dev/null differ diff --git a/data/sprites/official/mariocappy.1.zspr b/data/sprites/official/mariocappy.1.zspr deleted file mode 100644 index b888396d..00000000 Binary files a/data/sprites/official/mariocappy.1.zspr and /dev/null differ diff --git a/data/sprites/official/marisa.1.zspr b/data/sprites/official/marisa.1.zspr deleted file mode 100644 index 16b2a803..00000000 Binary files a/data/sprites/official/marisa.1.zspr and /dev/null differ diff --git a/data/sprites/official/matthias.1.zspr b/data/sprites/official/matthias.1.zspr deleted file mode 100644 index 062dae6d..00000000 Binary files a/data/sprites/official/matthias.1.zspr and /dev/null differ diff --git a/data/sprites/official/meatwad.1.zspr b/data/sprites/official/meatwad.1.zspr deleted file mode 100644 index a09a4adf..00000000 Binary files a/data/sprites/official/meatwad.1.zspr and /dev/null differ diff --git a/data/sprites/official/medallions.1.zspr b/data/sprites/official/medallions.1.zspr deleted file mode 100644 index dc4b04d1..00000000 Binary files a/data/sprites/official/medallions.1.zspr and /dev/null differ diff --git a/data/sprites/official/medli.1.zspr b/data/sprites/official/medli.1.zspr deleted file mode 100644 index 59284a36..00000000 Binary files a/data/sprites/official/medli.1.zspr and /dev/null differ diff --git a/data/sprites/official/megaman-x.2.zspr b/data/sprites/official/megaman-x.2.zspr deleted file mode 100644 index ffe75595..00000000 Binary files a/data/sprites/official/megaman-x.2.zspr and /dev/null differ diff --git a/data/sprites/official/metroid.1.zspr b/data/sprites/official/metroid.1.zspr deleted file mode 100644 index d81187cb..00000000 Binary files a/data/sprites/official/metroid.1.zspr and /dev/null differ diff --git a/data/sprites/official/mew.1.zspr b/data/sprites/official/mew.1.zspr deleted file mode 100644 index a06dc8d6..00000000 Binary files a/data/sprites/official/mew.1.zspr and /dev/null differ diff --git a/data/sprites/official/mike-jones.2.zspr b/data/sprites/official/mike-jones.2.zspr deleted file mode 100644 index 550fb213..00000000 Binary files a/data/sprites/official/mike-jones.2.zspr and /dev/null differ diff --git a/data/sprites/official/minish_link.1.zspr b/data/sprites/official/minish_link.1.zspr deleted file mode 100644 index 4b342c1a..00000000 Binary files a/data/sprites/official/minish_link.1.zspr and /dev/null differ diff --git a/data/sprites/official/minishcaplink.2.zspr b/data/sprites/official/minishcaplink.2.zspr deleted file mode 100644 index aaca256b..00000000 Binary files a/data/sprites/official/minishcaplink.2.zspr and /dev/null differ diff --git a/data/sprites/official/missingno.1.zspr b/data/sprites/official/missingno.1.zspr deleted file mode 100644 index 68e61b9b..00000000 Binary files a/data/sprites/official/missingno.1.zspr and /dev/null differ diff --git a/data/sprites/official/moblin.1.zspr b/data/sprites/official/moblin.1.zspr deleted file mode 100644 index 3e425e12..00000000 Binary files a/data/sprites/official/moblin.1.zspr and /dev/null differ diff --git a/data/sprites/official/modernlink.1.zspr b/data/sprites/official/modernlink.1.zspr deleted file mode 100644 index 6d5e68a4..00000000 Binary files a/data/sprites/official/modernlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/mog.2.zspr b/data/sprites/official/mog.2.zspr deleted file mode 100644 index a6ed2225..00000000 Binary files a/data/sprites/official/mog.2.zspr and /dev/null differ diff --git a/data/sprites/official/momiji.1.zspr b/data/sprites/official/momiji.1.zspr deleted file mode 100644 index 86a18586..00000000 Binary files a/data/sprites/official/momiji.1.zspr and /dev/null differ diff --git a/data/sprites/official/moosh.1.zspr b/data/sprites/official/moosh.1.zspr deleted file mode 100644 index 0a1e167a..00000000 Binary files a/data/sprites/official/moosh.1.zspr and /dev/null differ diff --git a/data/sprites/official/mouse.1.zspr b/data/sprites/official/mouse.1.zspr deleted file mode 100644 index 16ba884d..00000000 Binary files a/data/sprites/official/mouse.1.zspr and /dev/null differ diff --git a/data/sprites/official/ms-paintdog.1.zspr b/data/sprites/official/ms-paintdog.1.zspr deleted file mode 100644 index 75f5f541..00000000 Binary files a/data/sprites/official/ms-paintdog.1.zspr and /dev/null differ diff --git a/data/sprites/official/mushy.1.zspr b/data/sprites/official/mushy.1.zspr deleted file mode 100644 index a6c924a5..00000000 Binary files a/data/sprites/official/mushy.1.zspr and /dev/null differ diff --git a/data/sprites/official/naturelink.1.zspr b/data/sprites/official/naturelink.1.zspr deleted file mode 100644 index bdfd0efb..00000000 Binary files a/data/sprites/official/naturelink.1.zspr and /dev/null differ diff --git a/data/sprites/official/navi.1.zspr b/data/sprites/official/navi.1.zspr deleted file mode 100644 index 4621bf4a..00000000 Binary files a/data/sprites/official/navi.1.zspr and /dev/null differ diff --git a/data/sprites/official/navirou.2.zspr b/data/sprites/official/navirou.2.zspr deleted file mode 100644 index ea9d95a4..00000000 Binary files a/data/sprites/official/navirou.2.zspr and /dev/null differ diff --git a/data/sprites/official/ned-flanders.1.zspr b/data/sprites/official/ned-flanders.1.zspr deleted file mode 100644 index 78ed5bc4..00000000 Binary files a/data/sprites/official/ned-flanders.1.zspr and /dev/null differ diff --git a/data/sprites/official/negativelink.1.zspr b/data/sprites/official/negativelink.1.zspr deleted file mode 100644 index a3dd1566..00000000 Binary files a/data/sprites/official/negativelink.1.zspr and /dev/null differ diff --git a/data/sprites/official/neosad.1.zspr b/data/sprites/official/neosad.1.zspr deleted file mode 100644 index 7e95d7f7..00000000 Binary files a/data/sprites/official/neosad.1.zspr and /dev/null differ diff --git a/data/sprites/official/neslink.1.zspr b/data/sprites/official/neslink.1.zspr deleted file mode 100644 index 805b3162..00000000 Binary files a/data/sprites/official/neslink.1.zspr and /dev/null differ diff --git a/data/sprites/official/ness.1.zspr b/data/sprites/official/ness.1.zspr deleted file mode 100644 index b8b3de81..00000000 Binary files a/data/sprites/official/ness.1.zspr and /dev/null differ diff --git a/data/sprites/official/nia.1.zspr b/data/sprites/official/nia.1.zspr deleted file mode 100644 index 5d01ba4b..00000000 Binary files a/data/sprites/official/nia.1.zspr and /dev/null differ diff --git a/data/sprites/official/niddraig.1.zspr b/data/sprites/official/niddraig.1.zspr deleted file mode 100644 index d02794bc..00000000 Binary files a/data/sprites/official/niddraig.1.zspr and /dev/null differ diff --git a/data/sprites/official/niko.1.zspr b/data/sprites/official/niko.1.zspr deleted file mode 100644 index 5d39e6bb..00000000 Binary files a/data/sprites/official/niko.1.zspr and /dev/null differ diff --git a/data/sprites/official/oldman.2.zspr b/data/sprites/official/oldman.2.zspr deleted file mode 100644 index 1d47cdac..00000000 Binary files a/data/sprites/official/oldman.2.zspr and /dev/null differ diff --git a/data/sprites/official/ori.2.zspr b/data/sprites/official/ori.2.zspr deleted file mode 100644 index 10c1e462..00000000 Binary files a/data/sprites/official/ori.2.zspr and /dev/null differ diff --git a/data/sprites/official/outlinelink.1.zspr b/data/sprites/official/outlinelink.1.zspr deleted file mode 100644 index 50ae98bc..00000000 Binary files a/data/sprites/official/outlinelink.1.zspr and /dev/null differ diff --git a/data/sprites/official/parallelworldslink.1.zspr b/data/sprites/official/parallelworldslink.1.zspr deleted file mode 100644 index 71a9bdc1..00000000 Binary files a/data/sprites/official/parallelworldslink.1.zspr and /dev/null differ diff --git a/data/sprites/official/paula.1.zspr b/data/sprites/official/paula.1.zspr deleted file mode 100644 index 657752ea..00000000 Binary files a/data/sprites/official/paula.1.zspr and /dev/null differ diff --git a/data/sprites/official/peach.1.zspr b/data/sprites/official/peach.1.zspr deleted file mode 100644 index 7973f952..00000000 Binary files a/data/sprites/official/peach.1.zspr and /dev/null differ diff --git a/data/sprites/official/penguinlink.1.zspr b/data/sprites/official/penguinlink.1.zspr deleted file mode 100644 index 2fe01e49..00000000 Binary files a/data/sprites/official/penguinlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/pete.1.zspr b/data/sprites/official/pete.1.zspr deleted file mode 100644 index a3135615..00000000 Binary files a/data/sprites/official/pete.1.zspr and /dev/null differ diff --git a/data/sprites/official/phoenix-wright.1.zspr b/data/sprites/official/phoenix-wright.1.zspr deleted file mode 100644 index d7cb0be2..00000000 Binary files a/data/sprites/official/phoenix-wright.1.zspr and /dev/null differ diff --git a/data/sprites/official/pikachu.1.zspr b/data/sprites/official/pikachu.1.zspr deleted file mode 100644 index 0b8a88c4..00000000 Binary files a/data/sprites/official/pikachu.1.zspr and /dev/null differ diff --git a/data/sprites/official/pinkribbonlink.2.zspr b/data/sprites/official/pinkribbonlink.2.zspr deleted file mode 100644 index ba516f18..00000000 Binary files a/data/sprites/official/pinkribbonlink.2.zspr and /dev/null differ diff --git a/data/sprites/official/piranha_plant.1.zspr b/data/sprites/official/piranha_plant.1.zspr deleted file mode 100644 index 59bf4d0d..00000000 Binary files a/data/sprites/official/piranha_plant.1.zspr and /dev/null differ diff --git a/data/sprites/official/plagueknight.1.zspr b/data/sprites/official/plagueknight.1.zspr deleted file mode 100644 index 258bed7b..00000000 Binary files a/data/sprites/official/plagueknight.1.zspr and /dev/null differ diff --git a/data/sprites/official/pokey.1.zspr b/data/sprites/official/pokey.1.zspr deleted file mode 100644 index 4de17faf..00000000 Binary files a/data/sprites/official/pokey.1.zspr and /dev/null differ diff --git a/data/sprites/official/popoi.1.zspr b/data/sprites/official/popoi.1.zspr deleted file mode 100644 index 663d4dc1..00000000 Binary files a/data/sprites/official/popoi.1.zspr and /dev/null differ diff --git a/data/sprites/official/poppy.1.zspr b/data/sprites/official/poppy.1.zspr deleted file mode 100644 index 80d4ca69..00000000 Binary files a/data/sprites/official/poppy.1.zspr and /dev/null differ diff --git a/data/sprites/official/porg_knight.1.zspr b/data/sprites/official/porg_knight.1.zspr deleted file mode 100644 index 4d6f9635..00000000 Binary files a/data/sprites/official/porg_knight.1.zspr and /dev/null differ diff --git a/data/sprites/official/powerpuff_girl.1.zspr b/data/sprites/official/powerpuff_girl.1.zspr deleted file mode 100644 index fbf3c694..00000000 Binary files a/data/sprites/official/powerpuff_girl.1.zspr and /dev/null differ diff --git a/data/sprites/official/pridelink.2.zspr b/data/sprites/official/pridelink.2.zspr deleted file mode 100644 index 66231013..00000000 Binary files a/data/sprites/official/pridelink.2.zspr and /dev/null differ diff --git a/data/sprites/official/primm.1.zspr b/data/sprites/official/primm.1.zspr deleted file mode 100644 index e9ff2d05..00000000 Binary files a/data/sprites/official/primm.1.zspr and /dev/null differ diff --git a/data/sprites/official/princess_bubblegum.1.zspr b/data/sprites/official/princess_bubblegum.1.zspr deleted file mode 100644 index c46dcc0f..00000000 Binary files a/data/sprites/official/princess_bubblegum.1.zspr and /dev/null differ diff --git a/data/sprites/official/psyduck.2.zspr b/data/sprites/official/psyduck.2.zspr deleted file mode 100644 index c9e17117..00000000 Binary files a/data/sprites/official/psyduck.2.zspr and /dev/null differ diff --git a/data/sprites/official/pug.1.zspr b/data/sprites/official/pug.1.zspr deleted file mode 100644 index 60692711..00000000 Binary files a/data/sprites/official/pug.1.zspr and /dev/null differ diff --git a/data/sprites/official/purplechest-bottle.1.zspr b/data/sprites/official/purplechest-bottle.1.zspr deleted file mode 100644 index 8daed4d6..00000000 Binary files a/data/sprites/official/purplechest-bottle.1.zspr and /dev/null differ diff --git a/data/sprites/official/pyro.1.zspr b/data/sprites/official/pyro.1.zspr deleted file mode 100644 index 9037c8e4..00000000 Binary files a/data/sprites/official/pyro.1.zspr and /dev/null differ diff --git a/data/sprites/official/rainbowlink.1.zspr b/data/sprites/official/rainbowlink.1.zspr deleted file mode 100644 index bc8443f9..00000000 Binary files a/data/sprites/official/rainbowlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/rat.1.zspr b/data/sprites/official/rat.1.zspr deleted file mode 100644 index b4574c06..00000000 Binary files a/data/sprites/official/rat.1.zspr and /dev/null differ diff --git a/data/sprites/official/red-mage.1.zspr b/data/sprites/official/red-mage.1.zspr deleted file mode 100644 index 803a5b6f..00000000 Binary files a/data/sprites/official/red-mage.1.zspr and /dev/null differ diff --git a/data/sprites/official/remeer.1.zspr b/data/sprites/official/remeer.1.zspr deleted file mode 100644 index 8d7f245a..00000000 Binary files a/data/sprites/official/remeer.1.zspr and /dev/null differ diff --git a/data/sprites/official/rick.1.zspr b/data/sprites/official/rick.1.zspr deleted file mode 100644 index 93a163f6..00000000 Binary files a/data/sprites/official/rick.1.zspr and /dev/null differ diff --git a/data/sprites/official/robotlink.1.zspr b/data/sprites/official/robotlink.1.zspr deleted file mode 100644 index 8a1eed43..00000000 Binary files a/data/sprites/official/robotlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/rocko.1.zspr b/data/sprites/official/rocko.1.zspr deleted file mode 100644 index ab34f635..00000000 Binary files a/data/sprites/official/rocko.1.zspr and /dev/null differ diff --git a/data/sprites/official/rottytops.1.zspr b/data/sprites/official/rottytops.1.zspr deleted file mode 100644 index d4007ffb..00000000 Binary files a/data/sprites/official/rottytops.1.zspr and /dev/null differ diff --git a/data/sprites/official/rover.1.zspr b/data/sprites/official/rover.1.zspr deleted file mode 100644 index 8b9e9edd..00000000 Binary files a/data/sprites/official/rover.1.zspr and /dev/null differ diff --git a/data/sprites/official/roykoopa.1.zspr b/data/sprites/official/roykoopa.1.zspr deleted file mode 100644 index e1f9699f..00000000 Binary files a/data/sprites/official/roykoopa.1.zspr and /dev/null differ diff --git a/data/sprites/official/rumia.1.zspr b/data/sprites/official/rumia.1.zspr deleted file mode 100644 index dc037ae2..00000000 Binary files a/data/sprites/official/rumia.1.zspr and /dev/null differ diff --git a/data/sprites/official/rydia.1.zspr b/data/sprites/official/rydia.1.zspr deleted file mode 100644 index ff98ab56..00000000 Binary files a/data/sprites/official/rydia.1.zspr and /dev/null differ diff --git a/data/sprites/official/ryu.1.zspr b/data/sprites/official/ryu.1.zspr deleted file mode 100644 index 5c6d5411..00000000 Binary files a/data/sprites/official/ryu.1.zspr and /dev/null differ diff --git a/data/sprites/official/sailormoon.1.zspr b/data/sprites/official/sailormoon.1.zspr deleted file mode 100644 index 1120d3f4..00000000 Binary files a/data/sprites/official/sailormoon.1.zspr and /dev/null differ diff --git a/data/sprites/official/saitama.1.zspr b/data/sprites/official/saitama.1.zspr deleted file mode 100644 index acd9170d..00000000 Binary files a/data/sprites/official/saitama.1.zspr and /dev/null differ diff --git a/data/sprites/official/samus-sm.1.zspr b/data/sprites/official/samus-sm.1.zspr deleted file mode 100644 index c8fde01b..00000000 Binary files a/data/sprites/official/samus-sm.1.zspr and /dev/null differ diff --git a/data/sprites/official/samus.2.zspr b/data/sprites/official/samus.2.zspr deleted file mode 100644 index 81b0912f..00000000 Binary files a/data/sprites/official/samus.2.zspr and /dev/null differ diff --git a/data/sprites/official/samus_classic.1.zspr b/data/sprites/official/samus_classic.1.zspr deleted file mode 100644 index 6559e25c..00000000 Binary files a/data/sprites/official/samus_classic.1.zspr and /dev/null differ diff --git a/data/sprites/official/santalink.2.zspr b/data/sprites/official/santalink.2.zspr deleted file mode 100644 index 0e78fedb..00000000 Binary files a/data/sprites/official/santalink.2.zspr and /dev/null differ diff --git a/data/sprites/official/scholar.1.zspr b/data/sprites/official/scholar.1.zspr deleted file mode 100644 index bf697f16..00000000 Binary files a/data/sprites/official/scholar.1.zspr and /dev/null differ diff --git a/data/sprites/official/selan.1.zspr b/data/sprites/official/selan.1.zspr deleted file mode 100644 index eb3b0318..00000000 Binary files a/data/sprites/official/selan.1.zspr and /dev/null differ diff --git a/data/sprites/official/sevens1ns.1.zspr b/data/sprites/official/sevens1ns.1.zspr deleted file mode 100644 index d59a1b52..00000000 Binary files a/data/sprites/official/sevens1ns.1.zspr and /dev/null differ diff --git a/data/sprites/official/shadow.1.zspr b/data/sprites/official/shadow.1.zspr deleted file mode 100644 index fcd0d49b..00000000 Binary files a/data/sprites/official/shadow.1.zspr and /dev/null differ diff --git a/data/sprites/official/shadowsaku.2.zspr b/data/sprites/official/shadowsaku.2.zspr deleted file mode 100644 index 8972f9f2..00000000 Binary files a/data/sprites/official/shadowsaku.2.zspr and /dev/null differ diff --git a/data/sprites/official/shantae.1.zspr b/data/sprites/official/shantae.1.zspr deleted file mode 100644 index 03a1c7b9..00000000 Binary files a/data/sprites/official/shantae.1.zspr and /dev/null differ diff --git a/data/sprites/official/shuppet.1.zspr b/data/sprites/official/shuppet.1.zspr deleted file mode 100644 index 55a51ae9..00000000 Binary files a/data/sprites/official/shuppet.1.zspr and /dev/null differ diff --git a/data/sprites/official/shy-gal.1.zspr b/data/sprites/official/shy-gal.1.zspr deleted file mode 100644 index b86b27bc..00000000 Binary files a/data/sprites/official/shy-gal.1.zspr and /dev/null differ diff --git a/data/sprites/official/shy-guy.1.zspr b/data/sprites/official/shy-guy.1.zspr deleted file mode 100644 index 43ee0fe4..00000000 Binary files a/data/sprites/official/shy-guy.1.zspr and /dev/null differ diff --git a/data/sprites/official/sighn_waive.1.zspr b/data/sprites/official/sighn_waive.1.zspr deleted file mode 100644 index d961dc4d..00000000 Binary files a/data/sprites/official/sighn_waive.1.zspr and /dev/null differ diff --git a/data/sprites/official/slime.1.zspr b/data/sprites/official/slime.1.zspr deleted file mode 100644 index 711e459f..00000000 Binary files a/data/sprites/official/slime.1.zspr and /dev/null differ diff --git a/data/sprites/official/slowpoke.1.zspr b/data/sprites/official/slowpoke.1.zspr deleted file mode 100644 index d1b40e23..00000000 Binary files a/data/sprites/official/slowpoke.1.zspr and /dev/null differ diff --git a/data/sprites/official/snes-controller.1.zspr b/data/sprites/official/snes-controller.1.zspr deleted file mode 100644 index 5dd70f39..00000000 Binary files a/data/sprites/official/snes-controller.1.zspr and /dev/null differ diff --git a/data/sprites/official/sodacan.1.zspr b/data/sprites/official/sodacan.1.zspr deleted file mode 100644 index 93e6fb1e..00000000 Binary files a/data/sprites/official/sodacan.1.zspr and /dev/null differ diff --git a/data/sprites/official/solaire.1.zspr b/data/sprites/official/solaire.1.zspr deleted file mode 100644 index e216a7d9..00000000 Binary files a/data/sprites/official/solaire.1.zspr and /dev/null differ diff --git a/data/sprites/official/soldiersprite.1.zspr b/data/sprites/official/soldiersprite.1.zspr deleted file mode 100644 index d5e8ee35..00000000 Binary files a/data/sprites/official/soldiersprite.1.zspr and /dev/null differ diff --git a/data/sprites/official/sonic.1.zspr b/data/sprites/official/sonic.1.zspr deleted file mode 100644 index 55724219..00000000 Binary files a/data/sprites/official/sonic.1.zspr and /dev/null differ diff --git a/data/sprites/official/sora.1.zspr b/data/sprites/official/sora.1.zspr deleted file mode 100644 index c8d656fd..00000000 Binary files a/data/sprites/official/sora.1.zspr and /dev/null differ diff --git a/data/sprites/official/sora_kh1.1.zspr b/data/sprites/official/sora_kh1.1.zspr deleted file mode 100644 index e77c922d..00000000 Binary files a/data/sprites/official/sora_kh1.1.zspr and /dev/null differ diff --git a/data/sprites/official/spongebob.1.zspr b/data/sprites/official/spongebob.1.zspr deleted file mode 100644 index 714f6983..00000000 Binary files a/data/sprites/official/spongebob.1.zspr and /dev/null differ diff --git a/data/sprites/official/squall.1.zspr b/data/sprites/official/squall.1.zspr deleted file mode 100644 index b9cd9556..00000000 Binary files a/data/sprites/official/squall.1.zspr and /dev/null differ diff --git a/data/sprites/official/squirrel.1.zspr b/data/sprites/official/squirrel.1.zspr deleted file mode 100644 index 64e399a1..00000000 Binary files a/data/sprites/official/squirrel.1.zspr and /dev/null differ diff --git a/data/sprites/official/squirtle.1.zspr b/data/sprites/official/squirtle.1.zspr deleted file mode 100644 index 274bf1c7..00000000 Binary files a/data/sprites/official/squirtle.1.zspr and /dev/null differ diff --git a/data/sprites/official/stalfos.1.zspr b/data/sprites/official/stalfos.1.zspr deleted file mode 100644 index d4787a3b..00000000 Binary files a/data/sprites/official/stalfos.1.zspr and /dev/null differ diff --git a/data/sprites/official/stan.1.zspr b/data/sprites/official/stan.1.zspr deleted file mode 100644 index 5fd3eb11..00000000 Binary files a/data/sprites/official/stan.1.zspr and /dev/null differ diff --git a/data/sprites/official/staticlink.1.zspr b/data/sprites/official/staticlink.1.zspr deleted file mode 100644 index d0f1bc06..00000000 Binary files a/data/sprites/official/staticlink.1.zspr and /dev/null differ diff --git a/data/sprites/official/steamedhams.1.zspr b/data/sprites/official/steamedhams.1.zspr deleted file mode 100644 index bcae82fb..00000000 Binary files a/data/sprites/official/steamedhams.1.zspr and /dev/null differ diff --git a/data/sprites/official/superbomb.1.zspr b/data/sprites/official/superbomb.1.zspr deleted file mode 100644 index 1ed38ae3..00000000 Binary files a/data/sprites/official/superbomb.1.zspr and /dev/null differ diff --git a/data/sprites/official/superbunny.2.zspr b/data/sprites/official/superbunny.2.zspr deleted file mode 100644 index b842d1c3..00000000 Binary files a/data/sprites/official/superbunny.2.zspr and /dev/null differ diff --git a/data/sprites/official/supermeatboy.1.zspr b/data/sprites/official/supermeatboy.1.zspr deleted file mode 100644 index ad4368bb..00000000 Binary files a/data/sprites/official/supermeatboy.1.zspr and /dev/null differ diff --git a/data/sprites/official/susie.1.zspr b/data/sprites/official/susie.1.zspr deleted file mode 100644 index c1127b87..00000000 Binary files a/data/sprites/official/susie.1.zspr and /dev/null differ diff --git a/data/sprites/official/swatchy.1.zspr b/data/sprites/official/swatchy.1.zspr deleted file mode 100644 index 46795e9b..00000000 Binary files a/data/sprites/official/swatchy.1.zspr and /dev/null differ diff --git a/data/sprites/official/tasbot.1.zspr b/data/sprites/official/tasbot.1.zspr deleted file mode 100644 index b7278587..00000000 Binary files a/data/sprites/official/tasbot.1.zspr and /dev/null differ diff --git a/data/sprites/official/teatime.1.zspr b/data/sprites/official/teatime.1.zspr deleted file mode 100644 index 8953bc79..00000000 Binary files a/data/sprites/official/teatime.1.zspr and /dev/null differ diff --git a/data/sprites/official/terra.1.zspr b/data/sprites/official/terra.1.zspr deleted file mode 100644 index e24ca87a..00000000 Binary files a/data/sprites/official/terra.1.zspr and /dev/null differ diff --git a/data/sprites/official/tetra.1.zspr b/data/sprites/official/tetra.1.zspr deleted file mode 100644 index 77525f08..00000000 Binary files a/data/sprites/official/tetra.1.zspr and /dev/null differ diff --git a/data/sprites/official/tgh.1.zspr b/data/sprites/official/tgh.1.zspr deleted file mode 100644 index 929b8705..00000000 Binary files a/data/sprites/official/tgh.1.zspr and /dev/null differ diff --git a/data/sprites/official/thief.1.zspr b/data/sprites/official/thief.1.zspr deleted file mode 100644 index b6b0ffef..00000000 Binary files a/data/sprites/official/thief.1.zspr and /dev/null differ diff --git a/data/sprites/official/thomcrow.1.zspr b/data/sprites/official/thomcrow.1.zspr deleted file mode 100644 index 81bba95d..00000000 Binary files a/data/sprites/official/thomcrow.1.zspr and /dev/null differ diff --git a/data/sprites/official/tile.2.zspr b/data/sprites/official/tile.2.zspr deleted file mode 100644 index 38332bb0..00000000 Binary files a/data/sprites/official/tile.2.zspr and /dev/null differ diff --git a/data/sprites/official/tingle.1.zspr b/data/sprites/official/tingle.1.zspr deleted file mode 100644 index 9a53f8d2..00000000 Binary files a/data/sprites/official/tingle.1.zspr and /dev/null differ diff --git a/data/sprites/official/tmnt.1.zspr b/data/sprites/official/tmnt.1.zspr deleted file mode 100644 index 8f01c1db..00000000 Binary files a/data/sprites/official/tmnt.1.zspr and /dev/null differ diff --git a/data/sprites/official/toad.2.zspr b/data/sprites/official/toad.2.zspr deleted file mode 100644 index 6abca2d7..00000000 Binary files a/data/sprites/official/toad.2.zspr and /dev/null differ diff --git a/data/sprites/official/toadette.2.zspr b/data/sprites/official/toadette.2.zspr deleted file mode 100644 index 8c6498b2..00000000 Binary files a/data/sprites/official/toadette.2.zspr and /dev/null differ diff --git a/data/sprites/official/toadette_captain.1.zspr b/data/sprites/official/toadette_captain.1.zspr deleted file mode 100644 index e69f74a7..00000000 Binary files a/data/sprites/official/toadette_captain.1.zspr and /dev/null differ diff --git a/data/sprites/official/totem-links.1.zspr b/data/sprites/official/totem-links.1.zspr deleted file mode 100644 index e4ac6abc..00000000 Binary files a/data/sprites/official/totem-links.1.zspr and /dev/null differ diff --git a/data/sprites/official/trogdor.1.zspr b/data/sprites/official/trogdor.1.zspr deleted file mode 100644 index b37191ac..00000000 Binary files a/data/sprites/official/trogdor.1.zspr and /dev/null differ diff --git a/data/sprites/official/twilightprincesszelda.2.zspr b/data/sprites/official/twilightprincesszelda.2.zspr deleted file mode 100644 index 2487f44a..00000000 Binary files a/data/sprites/official/twilightprincesszelda.2.zspr and /dev/null differ diff --git a/data/sprites/official/two_faced.1.zspr b/data/sprites/official/two_faced.1.zspr deleted file mode 100644 index d504c321..00000000 Binary files a/data/sprites/official/two_faced.1.zspr and /dev/null differ diff --git a/data/sprites/official/ty.1.zspr b/data/sprites/official/ty.1.zspr deleted file mode 100644 index 1091b298..00000000 Binary files a/data/sprites/official/ty.1.zspr and /dev/null differ diff --git a/data/sprites/official/ultros.1.zspr b/data/sprites/official/ultros.1.zspr deleted file mode 100644 index bd312843..00000000 Binary files a/data/sprites/official/ultros.1.zspr and /dev/null differ diff --git a/data/sprites/official/valeera.1.zspr b/data/sprites/official/valeera.1.zspr deleted file mode 100644 index 090a6631..00000000 Binary files a/data/sprites/official/valeera.1.zspr and /dev/null differ diff --git a/data/sprites/official/vanillalink.1.zspr b/data/sprites/official/vanillalink.1.zspr deleted file mode 100644 index 409171fa..00000000 Binary files a/data/sprites/official/vanillalink.1.zspr and /dev/null differ diff --git a/data/sprites/official/vaporeon.1.zspr b/data/sprites/official/vaporeon.1.zspr deleted file mode 100644 index 55372722..00000000 Binary files a/data/sprites/official/vaporeon.1.zspr and /dev/null differ diff --git a/data/sprites/official/vegeta.1.zspr b/data/sprites/official/vegeta.1.zspr deleted file mode 100644 index b4f46019..00000000 Binary files a/data/sprites/official/vegeta.1.zspr and /dev/null differ diff --git a/data/sprites/official/vera.1.zspr b/data/sprites/official/vera.1.zspr deleted file mode 100644 index b8914365..00000000 Binary files a/data/sprites/official/vera.1.zspr and /dev/null differ diff --git a/data/sprites/official/vitreous.1.zspr b/data/sprites/official/vitreous.1.zspr deleted file mode 100644 index 947eff30..00000000 Binary files a/data/sprites/official/vitreous.1.zspr and /dev/null differ diff --git a/data/sprites/official/vivi.1.zspr b/data/sprites/official/vivi.1.zspr deleted file mode 100644 index a7ad1a5f..00000000 Binary files a/data/sprites/official/vivi.1.zspr and /dev/null differ diff --git a/data/sprites/official/vivian.1.zspr b/data/sprites/official/vivian.1.zspr deleted file mode 100644 index 9de1061f..00000000 Binary files a/data/sprites/official/vivian.1.zspr and /dev/null differ diff --git a/data/sprites/official/wario.1.zspr b/data/sprites/official/wario.1.zspr deleted file mode 100644 index f1a5aab7..00000000 Binary files a/data/sprites/official/wario.1.zspr and /dev/null differ diff --git a/data/sprites/official/will.1.zspr b/data/sprites/official/will.1.zspr deleted file mode 100644 index d3794969..00000000 Binary files a/data/sprites/official/will.1.zspr and /dev/null differ diff --git a/data/sprites/official/wizzrobe.2.zspr b/data/sprites/official/wizzrobe.2.zspr deleted file mode 100644 index f79195d2..00000000 Binary files a/data/sprites/official/wizzrobe.2.zspr and /dev/null differ diff --git a/data/sprites/official/wolf_link.1.zspr b/data/sprites/official/wolf_link.1.zspr deleted file mode 100644 index 5ee07dcb..00000000 Binary files a/data/sprites/official/wolf_link.1.zspr and /dev/null differ diff --git a/data/sprites/official/wolf_link_tp.1.zspr b/data/sprites/official/wolf_link_tp.1.zspr deleted file mode 100644 index 9627cd73..00000000 Binary files a/data/sprites/official/wolf_link_tp.1.zspr and /dev/null differ diff --git a/data/sprites/official/yoshi.1.zspr b/data/sprites/official/yoshi.1.zspr deleted file mode 100644 index 189ea390..00000000 Binary files a/data/sprites/official/yoshi.1.zspr and /dev/null differ diff --git a/data/sprites/official/yunica.1.zspr b/data/sprites/official/yunica.1.zspr deleted file mode 100644 index 57f1f416..00000000 Binary files a/data/sprites/official/yunica.1.zspr and /dev/null differ diff --git a/data/sprites/official/zandra.1.zspr b/data/sprites/official/zandra.1.zspr deleted file mode 100644 index d7e5012c..00000000 Binary files a/data/sprites/official/zandra.1.zspr and /dev/null differ diff --git a/data/sprites/official/zebraunicorn.1.zspr b/data/sprites/official/zebraunicorn.1.zspr deleted file mode 100644 index c06130ff..00000000 Binary files a/data/sprites/official/zebraunicorn.1.zspr and /dev/null differ diff --git a/data/sprites/official/zeck.1.zspr b/data/sprites/official/zeck.1.zspr deleted file mode 100644 index 630acd1a..00000000 Binary files a/data/sprites/official/zeck.1.zspr and /dev/null differ diff --git a/data/sprites/official/zelda.1.zspr b/data/sprites/official/zelda.1.zspr deleted file mode 100644 index 26ba1a05..00000000 Binary files a/data/sprites/official/zelda.1.zspr and /dev/null differ diff --git a/data/sprites/official/zerosuitsamus.2.zspr b/data/sprites/official/zerosuitsamus.2.zspr deleted file mode 100644 index 0e5a7d17..00000000 Binary files a/data/sprites/official/zerosuitsamus.2.zspr and /dev/null differ diff --git a/data/sprites/official/zora.2.zspr b/data/sprites/official/zora.2.zspr deleted file mode 100644 index 1ca568e1..00000000 Binary files a/data/sprites/official/zora.2.zspr and /dev/null differ diff --git a/data/sprites/unofficial/.gitignore b/data/sprites/unofficial/.gitignore deleted file mode 100644 index d6b7ef32..00000000 --- a/data/sprites/unofficial/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/data/sprites/unofficial/.gitkeep b/data/sprites/unofficial/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index a0fa6296..556a0d13 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -202,7 +202,7 @@ "intensity" : [ "Door Shuffle Intensity Level (default: %(default)s)", "1: Shuffles normal doors and spiral staircases", - "2: And shuffles open edges and straight staircases", + "2: And shuffles open edges and both types of straight staircases", "3: And shuffles dungeon lobbies", "random: Picks one of those at random" ], diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index b3140d40..5351cd42 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -60,7 +60,7 @@ "randomizer.dungeon.dungeonintensity": "Intensity Level", "randomizer.dungeon.dungeonintensity.1": "1: Normal Supertile and Spiral Stairs", - "randomizer.dungeon.dungeonintensity.2": "2: Open Edges and Straight Stairs", + "randomizer.dungeon.dungeonintensity.2": "2: Open Edges, Straight Stairs and In-Room Stairs", "randomizer.dungeon.dungeonintensity.3": "3: Dungeon Lobbies", "randomizer.dungeon.dungeonintensity.random": "Random", diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index be7a3422..d3699ee2 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -19,7 +19,7 @@ "random" ], "config": { - "width": 35 + "width": 45 } }, "potshuffle": { "type": "checkbox" }, diff --git a/resources/ci/common/common.py b/resources/ci/common/common.py index 7066fa8d..f2288fe2 100644 --- a/resources/ci/common/common.py +++ b/resources/ci/common/common.py @@ -1,6 +1,22 @@ import os # for env vars import stat # file statistics +global UBUNTU_VERSIONS +global DEFAULT_EVENT +global DEFAULT_REPO_SLUG +global FILENAME_CHECKS +global FILESIZE_CHECK +UBUNTU_VERSIONS = { + "latest": "focal", + "20.04": "focal", + "18.04": "bionic", + "16.04": "xenial" +} +DEFAULT_EVENT = "event" +DEFAULT_REPO_SLUG = "miketrethewey/ALttPDoorRandomizer" +FILENAME_CHECKS = [ "Gui", "DungeonRandomizer" ] +FILESIZE_CHECK = (6 * 1024 * 1024) # 6MB + # take number of bytes and convert to string with units measure def convert_bytes(num): for x in ["bytes","KB","MB","GB","TB","PB"]: @@ -16,9 +32,8 @@ def file_size(file_path): # prepare environment variables def prepare_env(): - DEFAULT_EVENT = "event" - DEFAULT_REPO_SLUG = "miketrethewey/ALttPDoorRandomizer" - + global DEFAULT_EVENT + global DEFAULT_REPO_SLUG env = {} # get app version @@ -33,7 +48,7 @@ def prepare_env(): env["BRANCH"] = os.getenv("TRAVIS_BRANCH","") env["GITHUB_ACTOR"] = os.getenv("GITHUB_ACTOR","MegaMan.EXE") env["GITHUB_SHA"] = os.getenv("GITHUB_SHA","") - env["GITHUB_RUN_ID"] = os.getenv("GITHUB_RUN_ID","") + env["GITHUB_RUN_NUMBER"] = os.getenv("GITHUB_RUN_NUMBER","") env["GITHUB_SHA_SHORT"] = env["GITHUB_SHA"] # commit data env["COMMIT_ID"] = os.getenv("TRAVIS_COMMIT",os.getenv("GITHUB_SHA","")) @@ -57,7 +72,7 @@ def prepare_env(): env["GITHUB_SHA_SHORT"] = env["GITHUB_SHA"][:7] # ci data - env["BUILD_NUMBER"] = os.getenv("TRAVIS_BUILD_NUMBER",env["GITHUB_RUN_ID"]) + env["BUILD_NUMBER"] = os.getenv("TRAVIS_BUILD_NUMBER",env["GITHUB_RUN_NUMBER"]) GITHUB_TAG = os.getenv("TRAVIS_TAG",os.getenv("GITHUB_TAG","")) OS_NAME = os.getenv("TRAVIS_OS_NAME",os.getenv("OS_NAME","")).replace("macOS","osx") @@ -68,10 +83,8 @@ def prepare_env(): OS_VERSION = OS_NAME[OS_NAME.find('-')+1:] OS_NAME = OS_NAME[:OS_NAME.find('-')] if OS_NAME == "linux" or OS_NAME == "ubuntu": - if OS_VERSION == "latest": - OS_VERSION = "bionic" - elif OS_VERSION == "16.04": - OS_VERSION = "xenial" + if OS_VERSION in UBUNTU_VERSIONS: + OS_VERSION = UBUNTU_VERSIONS[OS_VERSION] OS_DIST = OS_VERSION if OS_VERSION == "" and not OS_DIST == "" and not OS_DIST == "notset": @@ -115,8 +128,8 @@ def prepare_filename(BUILD_FILENAME): # find a binary file if it's executable # failing that, assume it's over 6MB def find_binary(listdir): - FILENAME_CHECKS = [ "Gui", "DungeonRandomizer" ] - FILESIZE_CHECK = (6 * 1024 * 1024) # 6MB + global FILENAME_CHECKS + global FILESIZE_CHECK BUILD_FILENAMES = [] executable = stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH diff --git a/resources/ci/common/prepare_binary.py b/resources/ci/common/prepare_binary.py index 583c7d7b..ff9b7c99 100644 --- a/resources/ci/common/prepare_binary.py +++ b/resources/ci/common/prepare_binary.py @@ -32,6 +32,8 @@ for BUILD_FILENAME in BUILD_FILENAMES: print("Dest Filename: " + DEST_FILENAME) if not BUILD_FILENAME == "": print("Build Filesize: " + common.file_size(BUILD_FILENAME)) + else: + exit(1) if not BUILD_FILENAME == "": move( diff --git a/resources/ci/common/prepare_release.py b/resources/ci/common/prepare_release.py index 5e32b410..c3869f2d 100644 --- a/resources/ci/common/prepare_release.py +++ b/resources/ci/common/prepare_release.py @@ -29,6 +29,11 @@ for dirname in ["resources","user","meta","manifests"]: if os.path.isdir(dirpath): os.chmod(dirpath,0o755) +# nuke git files +for git in [ os.path.join(".", ".gitattrubutes"), os.path.join(".", ".gitignore") ]: + if os.path.isfile(git): + os.remove(git) + # nuke travis file if it exists for travis in [ os.path.join(".", ".travis.yml"), os.path.join(".", ".travis.off") ]: if os.path.isfile(travis): @@ -95,7 +100,10 @@ if len(BUILD_FILENAMES) > 0: # .zip if windows # .tar.gz otherwise - ZIP_FILENAME = os.path.join("..","deploy",env["REPO_NAME"]) if len(BUILD_FILENAMES) > 1 else os.path.join("..","deploy",os.path.splitext(BUILD_FILENAME)[0]) + if len(BUILD_FILENAMES) > 1: + ZIP_FILENAME = os.path.join("..","deploy",env["REPO_NAME"]) + else: + ZIP_FILENAME = os.path.join("..","deploy",os.path.splitext(BUILD_FILENAME)[0]) if env["OS_NAME"] == "windows": make_archive(ZIP_FILENAME,"zip") ZIP_FILENAME += ".zip" @@ -125,3 +133,6 @@ else: print("No Zip to prepare: " + ZIP_FILENAME) print("Git tag: " + env["GITHUB_TAG"]) + +if (len(BUILD_FILENAMES) == 0) or (ZIP_FILENAME == ""): + exit(1) diff --git a/DungeonRandomizer.spec b/source/DungeonRandomizer.spec similarity index 85% rename from DungeonRandomizer.spec rename to source/DungeonRandomizer.spec index d7234682..beb2ecfc 100644 --- a/DungeonRandomizer.spec +++ b/source/DungeonRandomizer.spec @@ -3,7 +3,10 @@ import sys block_cipher = None -console = True +console = True # <--- change this to True to enable command prompt when the app runs + +if sys.platform.find("mac") or sys.platform.find("osx"): + console = False BINARY_SLUG = "DungeonRandomizer" @@ -27,13 +30,10 @@ def recurse_for_py_files(names_so_far): hiddenimports = [] binaries = [] -#if sys.platform.find("windows"): -# binaries.append(("ucrtbase.dll",".")) - -a = Analysis([f"./{BINARY_SLUG}.py"], +a = Analysis([f"../{BINARY_SLUG}.py"], pathex=[], binaries=binaries, - datas=[], + datas=[('../data/', 'data/')], hiddenimports=hiddenimports, hookspath=[], runtime_hooks=[], @@ -46,6 +46,7 @@ a = Analysis([f"./{BINARY_SLUG}.py"], # https://stackoverflow.com/questions/17034434/how-to-remove-exclude-modules-and-files-from-pyinstaller excluded_binaries = [ 'VCRUNTIME140.dll', + 'ucrtbase.dll', 'msvcp140.dll', 'mfc140u.dll'] a.binaries = TOC([x for x in a.binaries if x[0] not in excluded_binaries]) @@ -64,4 +65,4 @@ exe = EXE(pyz, strip=False, upx=True, runtime_tmpdir=None, - console=console ) # <--- change this to True to enable command prompt when the app runs + console=console ) diff --git a/Gui.spec b/source/Gui.spec similarity index 88% rename from Gui.spec rename to source/Gui.spec index 001e82b2..8b140a75 100644 --- a/Gui.spec +++ b/source/Gui.spec @@ -3,10 +3,11 @@ import sys block_cipher = None -console = True +console = True # <--- change this to True to enable command prompt when the app runs if sys.platform.find("mac") or sys.platform.find("osx"): console = False + BINARY_SLUG = "Gui" def recurse_for_py_files(names_so_far): @@ -29,13 +30,10 @@ def recurse_for_py_files(names_so_far): hiddenimports = [] binaries = [] -#if sys.platform.find("windows"): -# binaries.append(("ucrtbase.dll",".")) - -a = Analysis([f"./{BINARY_SLUG}.py"], +a = Analysis([f"../{BINARY_SLUG}.py"], pathex=[], binaries=binaries, - datas=[], + datas=[('../data/', 'data/')], hiddenimports=hiddenimports, hookspath=[], runtime_hooks=[], @@ -48,6 +46,7 @@ a = Analysis([f"./{BINARY_SLUG}.py"], # https://stackoverflow.com/questions/17034434/how-to-remove-exclude-modules-and-files-from-pyinstaller excluded_binaries = [ 'VCRUNTIME140.dll', + 'ucrtbase.dll', 'msvcp140.dll', 'mfc140u.dll'] a.binaries = TOC([x for x in a.binaries if x[0] not in excluded_binaries]) @@ -63,7 +62,8 @@ exe = EXE(pyz, name=BINARY_SLUG, debug=False, bootloader_ignore_signals=False, + icon='../data/ER.ico', strip=False, upx=True, runtime_tmpdir=None, - console=console ) # <--- change this to True to enable command prompt when the app runs + console=console ) diff --git a/source/classes/SpriteSelector.py b/source/classes/SpriteSelector.py index 1ab073ad..102e4351 100644 --- a/source/classes/SpriteSelector.py +++ b/source/classes/SpriteSelector.py @@ -31,6 +31,11 @@ class SpriteSelector(object): def open_official_sprite_listing(_evt): webbrowser.open("http://alttpr.com/sprite_preview") + def open_official_sprite_dir(_evt): + if not os.path.isdir(self.official_sprite_dir): + os.makedirs(self.official_sprite_dir) + open_file(self.official_sprite_dir) + def open_unofficial_sprite_dir(_evt): if not os.path.isdir(self.unofficial_sprite_dir): os.makedirs(self.unofficial_sprite_dir) @@ -42,14 +47,17 @@ class SpriteSelector(object): official_frametitle = Frame(self.window) official_title_text = Label(official_frametitle, text="Official Sprites") - official_title_link = Label(official_frametitle, text="(open)", fg="blue", cursor="hand2") official_title_text.pack(side=LEFT) + official_local_title_link = Label(official_frametitle, text="(open local)", fg="blue", cursor="hand2") + official_local_title_link.pack(side=LEFT) + official_local_title_link.bind("", open_official_sprite_dir) + official_title_link = Label(official_frametitle, text="(ALttPR)", fg="blue", cursor="hand2") official_title_link.pack(side=LEFT) official_title_link.bind("", open_official_sprite_listing) unofficial_frametitle = Frame(self.window) unofficial_title_text = Label(unofficial_frametitle, text="Unofficial Sprites") - unofficial_title_link = Label(unofficial_frametitle, text="(open)", fg="blue", cursor="hand2") + unofficial_title_link = Label(unofficial_frametitle, text="(open local)", fg="blue", cursor="hand2") unofficial_title_text.pack(side=LEFT) unofficial_title_link.pack(side=LEFT) unofficial_title_link.bind("", open_unofficial_sprite_dir) @@ -231,8 +239,6 @@ class SpriteSelector(object): @property def official_sprite_dir(self): -# if is_bundled(): -# return output_path(os.path.join("sprites","official")) return self.local_official_sprite_dir @property @@ -241,8 +247,6 @@ class SpriteSelector(object): @property def unofficial_sprite_dir(self): -# if is_bundled(): -# return output_path(os.path.join("sprites","unofficial")) return self.local_unofficial_sprite_dir @property diff --git a/build-dr.py b/source/meta/build-dr.py similarity index 91% rename from build-dr.py rename to source/meta/build-dr.py index 46f5b88a..6f26adb9 100644 --- a/build-dr.py +++ b/source/meta/build-dr.py @@ -4,7 +4,7 @@ import shutil import sys # Spec file -SPEC_FILE = os.path.join("DungeonRandomizer.spec") +SPEC_FILE = os.path.join(".", "source", "DungeonRandomizer.spec") # Destination is current dir DEST_DIRECTORY = '.' diff --git a/build-gui.py b/source/meta/build-gui.py similarity index 93% rename from build-gui.py rename to source/meta/build-gui.py index 6cc69228..ae284261 100644 --- a/build-gui.py +++ b/source/meta/build-gui.py @@ -4,7 +4,7 @@ import shutil import sys # Spec file -SPEC_FILE = os.path.join("Gui.spec") +SPEC_FILE = os.path.join(".", "source", "Gui.spec") # Destination is current dir DEST_DIRECTORY = '.'