From 300db22725512486f03127c34adf5b79a2948c90 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 5 May 2020 13:24:51 -0600 Subject: [PATCH] Some ER generation improvements Attempt at Attic Hint Tile Stonewall detection improved by not excluding drops --- DoorShuffle.py | 35 ++++++++++++++++------------------- Doors.py | 5 +++++ DungeonGenerator.py | 4 ++-- Dungeons.py | 6 +----- Main.py | 2 +- RELEASENOTES.md | 12 ++++++++++-- Regions.py | 3 ++- 7 files changed, 37 insertions(+), 30 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index ca18c529..2365a426 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -9,10 +9,10 @@ from functools import reduce from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier from Regions import key_only_locations from Dungeons import dungeon_regions, region_starts, split_region_starts, flexible_starts -from Dungeons import drop_entrances, dungeon_bigs, dungeon_keys, dungeon_hints +from Dungeons import dungeon_bigs, dungeon_keys, dungeon_hints from Items import ItemFactory from RoomData import DoorKind, PairedDoor -from DungeonGenerator import ExplorationState, convert_regions, generate_dungeon, validate_tr +from DungeonGenerator import ExplorationState, convert_regions, generate_dungeon, pre_validate from DungeonGenerator import create_dungeon_builders, split_dungeon_builder, simple_dungeon_builder from KeyDoorShuffle import analyze_dungeon, validate_vanilla_key_logic, build_key_layout, validate_key_layout @@ -150,11 +150,10 @@ def vanilla_key_logic(world, player): origin_list = list(entrances_map[builder.name]) find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, builder.name) - origin_list_sans_drops = remove_drop_origins(origin_list) - if len(origin_list_sans_drops) <= 0: + if len(origin_list) <= 0: if last_key == builder.name or loops > 1000: - origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name - raise Exception('Infinite loop detected for "%s" located at %s' % builder.name, origin_name) + 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)) sector_queue.append(builder) last_key = builder.name loops += 1 @@ -366,17 +365,16 @@ def main_dungeon_generation(dungeon_builders, recombinant_builders, connections_ name = ' '.join(builder.name.split(' ')[:-1]) origin_list = list(builder.entrance_list) find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, name) - origin_list_sans_drops = remove_drop_origins(origin_list) - if len(origin_list_sans_drops) <= 0 or name == "Turtle Rock" and not validate_tr(builder, origin_list_sans_drops, world, player): + if len(origin_list) <= 0 or not pre_validate(builder, origin_list, world, player): if last_key == builder.name or loops > 1000: - origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name - raise Exception('Infinite loop detected for "%s" located at %s' % builder.name, origin_name) + 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)) sector_queue.append(builder) last_key = builder.name loops += 1 else: logging.getLogger('').info('%s: %s', world.fish.translate("cli","cli","generating.dungeon"), builder.name) - ds = generate_dungeon(builder, origin_list_sans_drops, split_dungeon, world, player) + ds = generate_dungeon(builder, origin_list, split_dungeon, world, player) find_new_entrances(ds, entrances_map, connections, potentials, enabled_entrances, world, player) ds.name = name builder.master_sector = ds @@ -430,22 +428,18 @@ def find_enabled_origins(sectors, enabled, entrance_list, entrance_map, key): entrance_map[key].append(region.name) -def remove_drop_origins(entrance_list): - return [x for x in entrance_list if x not in drop_entrances] - - def find_new_entrances(sector, entrances_map, connections, potentials, enabled, world, player): for region in sector.regions: if region.name in connections.keys() and (connections[region.name] in potentials.keys() or connections[region.name].name in world.inaccessible_regions[player]): - enable_new_entrances(region, connections, potentials, enabled, world, player) + enable_new_entrances(region, connections, potentials, enabled, world, player, region) inverted_aga_check(entrances_map, connections, potentials, enabled, world, player) -def enable_new_entrances(region, connections, potentials, enabled, world, player): +def enable_new_entrances(region, connections, potentials, enabled, world, player, region_enabler): new_region = connections[region.name] if new_region in potentials.keys(): for potential in potentials.pop(new_region): - enabled[potential] = (region.name, region.dungeon) + enabled[potential] = (region_enabler.name, region_enabler.dungeon) # see if this unexplored region connects elsewhere queue = deque(new_region.exits) visited = set() @@ -467,9 +461,10 @@ def inverted_aga_check(entrances_map, connections, potentials, enabled, world, p if 'Agahnims Tower' in entrances_map.keys() or aga_tower_enabled(enabled): for region in list(potentials.keys()): if region.name == 'Hyrule Castle Ledge': + enabler = world.get_region('Tower Agahnim 1', player) for r_name in potentials[region]: new_region = world.get_region(r_name, player) - enable_new_entrances(new_region, connections, potentials, enabled, world, player) + enable_new_entrances(new_region, connections, potentials, enabled, world, player, enabler) def aga_tower_enabled(enabled): @@ -1374,6 +1369,8 @@ logical_connections = [ ('Thieves Hellway Crystal Orange Barrier', 'Thieves Hellway'), ('Thieves Hellway Blue Barrier', 'Thieves Hellway N Crystal'), ('Thieves Hellway Crystal Blue Barrier', 'Thieves Hellway'), + ('Thieves Attic Orange Barrier', 'Thieves Attic Hint'), + ('Thieves Attic Hint Orange Barrier', 'Thieves Attic'), ('Thieves Basement Block Path', 'Thieves Blocked Entry'), ('Thieves Blocked Entry Path', 'Thieves Basement Block'), ('Thieves Conveyor Bridge Block Path', 'Thieves Conveyor Block'), diff --git a/Doors.py b/Doors.py index 3c9125be..5151a244 100644 --- a/Doors.py +++ b/Doors.py @@ -588,6 +588,8 @@ def create_doors(world, player): create_door(player, 'Thieves Spike Switch Up Stairs', Sprl).dir(Up, 0xab, 0, HTH).ss(Z, 0x1a, 0x6c, True, True).small_key().pos(0), create_door(player, 'Thieves Attic Down Stairs', Sprl).dir(Dn, 0x64, 0, HTH).ss(Z, 0x11, 0x80, True, True), create_door(player, 'Thieves Attic ES', Intr).dir(Ea, 0x64, Bot, High).pos(0), + create_door(player, 'Thieves Attic Orange Barrier', Lgcl), + create_door(player, 'Thieves Attic Hint Orange Barrier', Lgcl), create_door(player, 'Thieves Cricket Hall Left WS', Intr).dir(We, 0x64, Bot, High).pos(0), create_door(player, 'Thieves Cricket Hall Left Edge', Open).dir(Ea, 0x64, None, High).edge(0, X, 0x30), create_door(player, 'Thieves Cricket Hall Right Edge', Open).dir(We, 0x65, None, High).edge(0, Z, 0x30), @@ -1136,6 +1138,9 @@ def create_doors(world, player): world.get_door('Thieves Triple Bypass EN', player).barrier(CrystalBarrier.Blue) world.get_door('Thieves Hellway Orange Barrier', player).barrier(CrystalBarrier.Orange) world.get_door('Thieves Hellway Crystal Orange Barrier', player).barrier(CrystalBarrier.Orange) + world.get_door('Thieves Hellway Crystal Orange Barrier', player).barrier(CrystalBarrier.Orange) + world.get_door('Thieves Attic Orange Barrier', player).barrier(CrystalBarrier.Orange) + world.get_door('Thieves Attic Hint Orange Barrier', player).barrier(CrystalBarrier.Orange) world.get_door('Ice Bomb Drop SE', player).c_switch() world.get_door('Ice Conveyor SW', player).c_switch() diff --git a/DungeonGenerator.py b/DungeonGenerator.py index fb07b10f..5a51fa3a 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -24,8 +24,8 @@ class GraphPiece: self.possible_bk_locations = set() -# Turtle Rock shouldn't be generated until the Big Chest entrance is reachable -def validate_tr(builder, entrance_region_names, world, player): +# Dungeons shouldn't be generated until all entrances are appropriately accessible +def pre_validate(builder, entrance_region_names, world, player): entrance_regions = convert_regions(entrance_region_names, world, player) proposed_map = {} doors_to_connect = {} diff --git a/Dungeons.py b/Dungeons.py index 380c9898..03dbfa61 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -238,7 +238,7 @@ thieves_regions = [ 'Thieves Big Chest Nook', 'Thieves Hallway', 'Thieves Boss', 'Thieves Pot Alcove Mid', 'Thieves Pot Alcove Bottom', 'Thieves Pot Alcove Top', 'Thieves Conveyor Maze', 'Thieves Spike Track', 'Thieves Hellway', 'Thieves Hellway N Crystal', 'Thieves Hellway S Crystal', 'Thieves Triple Bypass', 'Thieves Spike Switch', - 'Thieves Attic', 'Thieves Cricket Hall Left', 'Thieves Cricket Hall Right', 'Thieves Attic Window', + 'Thieves Attic', 'Thieves Attic Hint', 'Thieves Cricket Hall Left', 'Thieves Cricket Hall Right', 'Thieves Attic Window', 'Thieves Basement Block', 'Thieves Blocked Entry', 'Thieves Lonely Zazak', 'Thieves Blind\'s Cell', 'Thieves Conveyor Bridge', 'Thieves Conveyor Block', 'Thieves Big Chest Room', 'Thieves Trap' ] @@ -347,10 +347,6 @@ flexible_starts = { 'Skull Woods': ['Skull Left Drop', 'Skull Pinball'] } -drop_entrances = [ - 'Sewers Rat Path', 'Skull Pinball', 'Skull Left Drop', 'Sanctuary' # Pot circle, Back drop have unique access -] - dungeon_keys = { 'Hyrule Castle': 'Small Key (Escape)', 'Eastern Palace': 'Small Key (Eastern Palace)', diff --git a/Main.py b/Main.py index 3bc3458c..5e181f82 100644 --- a/Main.py +++ b/Main.py @@ -24,7 +24,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute from ItemList import generate_itempool, difficulties, fill_prizes from Utils import output_path, parse_player_names -__version__ = '0.1.0.0-u' +__version__ = '0.1.0.1-u' class EnemizerError(RuntimeError): pass diff --git a/RELEASENOTES.md b/RELEASENOTES.md index bc017df8..347f98db 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,8 +1,16 @@ # New Features -* None yet +### Experimental features + +* Open "Edge" transitions can now be linked with normal doors +* "Straight" staircases (the ones similar to normal doors) can be linked with both normal doors and edges # Bug Fixes * Crossed Dungeon generation improvements -* Fix for Animated Tiles in crossed dungeon \ No newline at end of file +* Fix for Animated Tiles in crossed dungeon +* Stonewall hardlock no longer reachable from certain drops (Sewer Drop, some Skull Woods drops) that were previously possible + +##### In Progress + +* ~~TT Attic Hint tile should have a crystal switch accessible now~~ \ No newline at end of file diff --git a/Regions.py b/Regions.py index a995086c..cbe722de 100644 --- a/Regions.py +++ b/Regions.py @@ -473,7 +473,8 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Thieves Hellway S Crystal', 'Thieves\' Town', None, ['Thieves Hellway Crystal Orange Barrier', 'Thieves Hellway Crystal ES']), create_dungeon_region(player, 'Thieves Triple Bypass', 'Thieves\' Town', None, ['Thieves Triple Bypass WN', 'Thieves Triple Bypass EN', 'Thieves Triple Bypass SE']), create_dungeon_region(player, 'Thieves Spike Switch', 'Thieves\' Town', ['Thieves\' Town - Spike Switch Pot Key'], ['Thieves Spike Switch SW', 'Thieves Spike Switch Up Stairs']), - create_dungeon_region(player, 'Thieves Attic', 'Thieves\' Town', None, ['Thieves Attic Down Stairs', 'Thieves Attic ES']), + create_dungeon_region(player, 'Thieves Attic', 'Thieves\' Town', None, ['Thieves Attic Down Stairs', 'Thieves Attic ES', 'Thieves Attic Orange Barrier']), + create_dungeon_region(player, 'Thieves Attic Hint', 'Thieves\' Town', None, ['Thieves Attic Hint Orange Barrier']), create_dungeon_region(player, 'Thieves Cricket Hall Left', 'Thieves\' Town', None, ['Thieves Cricket Hall Left WS', 'Thieves Cricket Hall Left Edge']), create_dungeon_region(player, 'Thieves Cricket Hall Right', 'Thieves\' Town', None, ['Thieves Cricket Hall Right Edge', 'Thieves Cricket Hall Right ES']), create_dungeon_region(player, 'Thieves Attic Window', 'Thieves\' Town', ['Thieves\' Town - Attic', 'Attic Cracked Floor'], ['Thieves Attic Window WS']),