diff --git a/DoorShuffle.py b/DoorShuffle.py index 3c614030..922142f4 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -488,6 +488,7 @@ 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? @@ -505,6 +506,7 @@ def connect_portal_copy(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) def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False): @@ -1720,12 +1722,10 @@ def shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, w 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) - world.spoiler.set_door_type(chosen.name + ' <-> ' + chosen.dest.name, DoorKind.Dashable, 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) - world.spoiler.set_door_type(chosen.name + ' <-> ' + chosen.dest.name, DoorKind.Bombable, player) all_candidates.remove(chosen) for excluded in all_candidates: remove_pair_type_if_present(excluded, world, player) @@ -1863,12 +1863,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: @@ -1937,13 +1937,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) diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 6d70eada..d14715b2 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -619,7 +619,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 @@ -1575,6 +1575,8 @@ 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) choices = random.sample(sector_list, k=len(population)) for i, choice in enumerate(choices): diff --git a/ItemList.py b/ItemList.py index 6f4c172c..7d914774 100644 --- a/ItemList.py +++ b/ItemList.py @@ -872,6 +872,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/RELEASENOTES.md b/RELEASENOTES.md index b48a6dc5..7f440ea6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -99,6 +99,12 @@ testing to verify logic is all good. # Bug Fixes +* 2.0.20u + * Problem with Desert Wall not being pre-opened in intensity 3 fixed +* 2.0.19u + * Generation improvement + * Possible fix for shop vram corruption + * The Cane of Byrna does not count as a chest key anymore * 2.0.18u * Generation improvements * Bombs/Dash doors more consistent with the amount in vanilla. diff --git a/Rom.py b/Rom.py index 4d24a0c7..aa14ebc0 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '7264ffb7c430dde5d6bfe6030b79a575' +RANDOMIZERBASEHASH = '30147375153cc57197805eddf38c2a23' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index c0d427e8..74ee4e9a 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ