diff --git a/DoorShuffle.py b/DoorShuffle.py index 383a9de9..2a072f92 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -7,7 +7,7 @@ from enum import unique, Flag from typing import DefaultDict, Dict, List from functools import reduce -from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier, DungeonInfo +from BaseClasses import RegionType, Region, Door, DoorType, Direction, Sector, CrystalBarrier, DungeonInfo 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 @@ -134,7 +134,7 @@ def create_door_spoiler(world, player): DoorType.StraightStairs] and door_a not in done: done.add(door_a) door_b = door_a.dest - if door_b: + if door_b and not isinstance(door_b, Region): done.add(door_b) if not door_a.blocked and not door_b.blocked: world.spoiler.set_door(door_a.name, door_b.name, 'both', player, builder.name) @@ -338,7 +338,7 @@ def choose_portals(world, player): reachable_portals = [] inaccessible_portals = [] for portal in portal_list: - placeholder = world.get_region(portal + ' Placeholder', player) + placeholder = world.get_region(portal + ' Portal', player) portal_region = placeholder.exits[0].connected_region name = portal_region.name if portal_region.type == RegionType.LightWorld: @@ -431,7 +431,7 @@ def analyze_portals(world, player): reachable_portals = [] inaccessible_portals = [] for portal in portal_list: - placeholder = world.get_region(portal + ' Placeholder', player) + placeholder = world.get_region(portal + ' Portal', player) portal_region = placeholder.exits[0].connected_region name = portal_region.name if portal_region.type == RegionType.LightWorld: @@ -466,42 +466,37 @@ def analyze_portals(world, player): def connect_portal(portal, world, player): - ent, ext = portal_map[portal.name] + 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 + # 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) - target_exit.parent_region = portal_entrance.parent_region - portal_entrance.connected_region = target_exit.connected_region - placeholder = world.get_region(portal.name + ' Placeholder', player) - if len(placeholder.entrances) > 0: - edit_entrance = placeholder.entrances[0] - else: - edit_entrance = world.get_entrance(ent, player) - entrance_region = portal_entrance.parent_region - old_region = edit_entrance.connected_region - edit_entrance.connected_region = entrance_region - entrance_region.exits.remove(portal_entrance) - entrance_region.exits.append(target_exit) - entrance_region.entrances.append(edit_entrance) - old_region.entrances.remove(edit_entrance) - world.regions.remove(placeholder) + portal_entrance.connected_region = target_exit.parent_region + portal_region = world.get_region(portal.name + ' Portal', player) + portal_region.entrances.append(portal_entrance) + 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) +# todo: remove this? def connect_portal_copy(portal, world, player): - ent, ext = portal_map[portal.name] + 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) - entrance_region = portal_entrance.parent_region - entrance_region.exits.remove(portal_entrance) - entrance_region.exits.append(target_exit) - target_exit.parent_region = entrance_region - - placeholder = world.get_region(portal.name + ' Placeholder', player) - world.regions.remove(placeholder) + portal_entrance.connected_region = target_exit.parent_region + portal_region = world.get_region(portal.name + ' Portal', player) + portal_region.entrances.append(portal_entrance) + 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) def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False): @@ -760,7 +755,10 @@ def determine_entrance_list(world, player): portal = world.get_portal(portal_name, player) r_names[portal.door.entrance.parent_region.name] = portal for region_name, portal in r_names.items(): - region = world.get_region(region_name, player) + if portal: + region = world.get_region(portal.name + ' Portal', player) + else: + region = world.get_region(region_name, player) for ent in region.entrances: parent = ent.parent_region if (parent.type != RegionType.Dungeon and parent.name != 'Menu') or parent.name == 'Sewer Drop': @@ -821,7 +819,7 @@ def enable_new_entrances(region, connections, potentials, enabled, world, player if region_name in connections.keys() and connections[region_name] in potentials.keys(): for potential in potentials.pop(connections[region_name]): enabled[potential] = (region.name, region.dungeon) - if ext.connected_region.name in world.inaccessible_regions[player]: + if ext.connected_region.name in world.inaccessible_regions[player] or ext.connected_region.name.endswith(' Portal'): for new_exit in ext.connected_region.exits: if new_exit not in visited: queue.append(new_exit) @@ -1062,10 +1060,17 @@ def check_entrance_fixes(world, player): del checks['Ganons Tower'] for ent_name, key in checks.items(): entrance = world.get_entrance(ent_name, player) - if entrance.connected_region.dungeon: - layout = world.dungeon_layouts[player][entrance.connected_region.dungeon.name] + dungeon = entrance.connected_region.dungeon + if dungeon: + layout = world.dungeon_layouts[player][dungeon.name] if 'Sanctuary' in layout.master_sector.region_set(): - world.force_fix[player][key] = True + portal = None + for portal_name in dungeon_portals[dungeon.name]: + test_portal = world.get_portal(portal_name, player) + if entrance.connected_region == test_portal.door.entrance.connected_region: + portal = test_portal + break + world.force_fix[player][key] = portal def palette_assignment(world, player): @@ -1128,7 +1133,8 @@ def palette_assignment(world, player): room.palette = 0x1d for connection in ['Sanctuary S', 'Sanctuary N']: adjacent = world.get_entrance(connection, player) - if adjacent.door.dest and adjacent.door.dest.entrance.parent_region.type == RegionType.Dungeon: + adj_dest = adjacent.door.dest + if adj_dest and isinstance(adj_dest, Door) and adj_dest.entrance.parent_region.type == RegionType.Dungeon: if adjacent.door and adjacent.door.dest and adjacent.door.dest.roomIndex >= 0: room = world.get_room(adjacent.door.dest.roomIndex, player) room.palette = 0x1d @@ -1767,13 +1773,19 @@ def valid_inaccessible_region(r): def add_inaccessible_doors(world, player): if world.mode[player] == 'standard': - create_door(world, player, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Ledge') - create_door(world, player, 'Hyrule Castle Entrance (West)', 'Hyrule Castle Ledge') + create_doors_for_inaccessible_region('Hyrule Castle Ledge', world, player) # todo: ignore standard mode hyrule castle ledge? for inaccessible_region in world.inaccessible_regions[player]: - region = world.get_region(inaccessible_region, player) - for ext in region.exits: - create_door(world, player, ext.name, region.name) + create_doors_for_inaccessible_region(inaccessible_region, world, player) + + +def create_doors_for_inaccessible_region(inaccessible_region, world, player): + region = world.get_region(inaccessible_region, player) + for ext in region.exits: + create_door(world, player, ext.name, region.name) + if ext.connected_region.name.endswith(' Portal'): + for more_exts in ext.connected_region.exits: + create_door(world, player, more_exts.name, ext.connected_region.name) def create_door(world, player, entName, region_name): @@ -2731,31 +2743,31 @@ palette_non_influencers = { portal_map = { - 'Sanctuary': ('Sanctuary', 'Sanctuary Exit'), - 'Hyrule Castle West': ('Hyrule Castle Entrance (West)', 'Hyrule Castle Exit (West)'), - 'Hyrule Castle South': ('Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)'), - 'Hyrule Castle East': ('Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)'), - 'Eastern': ('Eastern Palace', 'Eastern Palace Exit'), - 'Desert West': ('Desert Palace Entrance (West)', 'Desert Palace Exit (West)'), - 'Desert South': ('Desert Palace Entrance (South)', 'Desert Palace Exit (South)'), - 'Desert East': ('Desert Palace Entrance (East)', 'Desert Palace Exit (East)'), - 'Desert Back': ('Desert Palace Entrance (North)', 'Desert Palace Exit (North)'), - 'Turtle Rock Lazy Eyes': ('Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)'), - 'Turtle Rock Eye Bridge': ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Isolated Ledge Exit'), - 'Turtle Rock Chest': ('Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)'), - 'Agahnims Tower': ('Agahnims Tower', 'Agahnims Tower Exit'), - 'Swamp': ('Swamp Palace', 'Swamp Palace Exit'), - 'Palace of Darkness': ('Palace of Darkness', 'Palace of Darkness Exit'), - 'Mire': ('Misery Mire', 'Misery Mire Exit'), - 'Skull 2 West': ('Skull Woods Second Section Door (West)', 'Skull Woods Second Section Exit (West)'), - 'Skull 2 East': ('Skull Woods Second Section Door (East)', 'Skull Woods Second Section Exit (East)'), - 'Skull 1': ('Skull Woods First Section Door', 'Skull Woods First Section Exit'), - 'Skull 3': ('Skull Woods Final Section', 'Skull Woods Final Section Exit'), - 'Ice': ('Ice Palace', 'Ice Palace Exit'), - 'Hera': ('Tower of Hera', 'Tower of Hera Exit'), - 'Thieves Town': ('Thieves Town', 'Thieves Town Exit'), - 'Turtle Rock Main': ('Turtle Rock', 'Turtle Rock Exit (Front)'), - 'Ganons Tower': ('Ganons Tower', 'Ganons Tower Exit'), + 'Sanctuary': ('Sanctuary', 'Sanctuary Exit', 'Enter HC (Sanc)'), + 'Hyrule Castle West': ('Hyrule Castle Entrance (West)', 'Hyrule Castle Exit (West)', 'Enter HC (West)'), + 'Hyrule Castle South': ('Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', 'Enter HC (South)'), + 'Hyrule Castle East': ('Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', 'Enter HC (East)'), + 'Eastern': ('Eastern Palace', 'Eastern Palace Exit', 'Enter Eastern Palace'), + 'Desert West': ('Desert Palace Entrance (West)', 'Desert Palace Exit (West)', 'Enter Desert (West)'), + 'Desert South': ('Desert Palace Entrance (South)', 'Desert Palace Exit (South)', 'Enter Desert (South)'), + 'Desert East': ('Desert Palace Entrance (East)', 'Desert Palace Exit (East)', 'Enter Desert (East)'), + 'Desert Back': ('Desert Palace Entrance (North)', 'Desert Palace Exit (North)', 'Enter Desert (North)'), + 'Turtle Rock Lazy Eyes': ('Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', 'Enter Turtle Rock (Lazy Eyes)'), + 'Turtle Rock Eye Bridge': ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Isolated Ledge Exit', 'Enter Turtle Rock (Laser Bridge)'), + 'Turtle Rock Chest': ('Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', 'Enter Turtle Rock (Chest)'), + 'Agahnims Tower': ('Agahnims Tower', 'Agahnims Tower Exit', 'Enter Agahnims Tower'), + 'Swamp': ('Swamp Palace', 'Swamp Palace Exit', 'Enter Swamp'), + 'Palace of Darkness': ('Palace of Darkness', 'Palace of Darkness Exit', 'Enter Palace of Darkness'), + 'Mire': ('Misery Mire', 'Misery Mire Exit', 'Enter Misery Mire'), + 'Skull 2 West': ('Skull Woods Second Section Door (West)', 'Skull Woods Second Section Exit (West)', 'Enter Skull Woods 2 (West)'), + 'Skull 2 East': ('Skull Woods Second Section Door (East)', 'Skull Woods Second Section Exit (East)', 'Enter Skull Woods 2 (East)'), + 'Skull 1': ('Skull Woods First Section Door', 'Skull Woods First Section Exit', 'Enter Skull Woods 1'), + 'Skull 3': ('Skull Woods Final Section', 'Skull Woods Final Section Exit', 'Enter Skull Woods 3'), + 'Ice': ('Ice Palace', 'Ice Palace Exit', 'Enter Ice Palace'), + 'Hera': ('Tower of Hera', 'Tower of Hera Exit', 'Enter Hera'), + 'Thieves Town': ('Thieves Town', 'Thieves Town Exit', 'Enter Thieves Town'), + 'Turtle Rock Main': ('Turtle Rock', 'Turtle Rock Exit (Front)', 'Enter Turtle Rock (Main)'), + 'Ganons Tower': ('Ganons Tower', 'Ganons Tower Exit', 'Enter Ganons Tower'), } split_portals = { diff --git a/Dungeons.py b/Dungeons.py index c22a0ac6..c33b38e8 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -169,7 +169,9 @@ hyrule_castle_regions = [ 'Hyrule Dungeon Armory Main', 'Hyrule Dungeon Armory Boomerang', 'Hyrule Dungeon Armory North Branch', 'Hyrule Dungeon Staircase', 'Hyrule Dungeon Cellblock', 'Hyrule Dungeon Cell', 'Sewers Behind Tapestry', 'Sewers Rope Room', 'Sewers Dark Cross', 'Sewers Water', 'Sewers Key Rat', 'Sewers Rat Path', - 'Sewers Secret Room Blocked Path', 'Sewers Secret Room', 'Sewers Yet More Rats', 'Sewers Pull Switch', 'Sanctuary' + 'Sewers Secret Room Blocked Path', 'Sewers Secret Room', 'Sewers Yet More Rats', 'Sewers Pull Switch', 'Sanctuary', + 'Sanctuary Portal', 'Hyrule Castle West Portal', 'Hyrule Castle South Portal', 'Hyrule Castle East Portal' + ] eastern_regions = [ @@ -179,7 +181,7 @@ eastern_regions = [ 'Eastern Compass Room', 'Eastern Hint Tile', 'Eastern Hint Tile Blocked Path', 'Eastern Courtyard', 'Eastern Fairies', 'Eastern Map Valley', 'Eastern Dark Square', 'Eastern Dark Pots', 'Eastern Big Key', 'Eastern Darkness', 'Eastern Rupees', 'Eastern Attic Start', 'Eastern False Switches', 'Eastern Cannonball Hell', - 'Eastern Single Eyegore', 'Eastern Duo Eyegores', 'Eastern Boss' + 'Eastern Single Eyegore', 'Eastern Duo Eyegores', 'Eastern Boss', 'Eastern Portal' ] desert_regions = [ @@ -188,20 +190,21 @@ desert_regions = [ 'Desert North Hall', 'Desert Map Room', 'Desert Sandworm Corner', 'Desert Bonk Torch', 'Desert Circle of Pots', 'Desert Big Chest Room', 'Desert West Wing', 'Desert West Lobby', 'Desert Fairy Fountain', 'Desert Back Lobby', 'Desert Tiles 1', 'Desert Bridge', 'Desert Four Statues', 'Desert Beamos Hall', 'Desert Tiles 2', - 'Desert Wall Slide', 'Desert Boss' + 'Desert Wall Slide', 'Desert Boss', 'Desert West Portal', 'Desert South Portal', 'Desert East Portal', + 'Desert Back Portal' ] hera_regions = [ 'Hera Lobby', 'Hera Basement Cage', 'Hera Tile Room', 'Hera Tridorm', 'Hera Torches', 'Hera Beetles', 'Hera Startile Corner', 'Hera Startile Wide', 'Hera 4F', 'Hera Big Chest Landing', 'Hera 5F', - 'Hera Fairies', 'Hera Boss' + 'Hera Fairies', 'Hera Boss', 'Hera Portal' ] tower_regions = [ 'Tower Lobby', 'Tower Gold Knights', 'Tower Room 03', 'Tower Lone Statue', 'Tower Dark Maze', 'Tower Dark Chargers', 'Tower Dual Statues', 'Tower Dark Pits', 'Tower Dark Archers', 'Tower Red Spears', 'Tower Red Guards', 'Tower Circle of Pots', 'Tower Pacifist Run', 'Tower Push Statue', 'Tower Catwalk', 'Tower Antechamber', - 'Tower Altar', 'Tower Agahnim 1' + 'Tower Altar', 'Tower Agahnim 1', 'Agahnims Tower Portal' ] pod_regions = [ @@ -211,7 +214,7 @@ pod_regions = [ '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' + 'PoD Dark Alley', 'PoD Callback', 'PoD Boss', 'Palace of Darkness Portal' ] swamp_regions = [ @@ -223,7 +226,8 @@ swamp_regions = [ 'Swamp West Shallows', 'Swamp West Block Path', 'Swamp West Ledge', 'Swamp Barrier Ledge', 'Swamp Barrier', 'Swamp Attic', 'Swamp Push Statue', 'Swamp Shooters', 'Swamp Left Elbow', 'Swamp Right Elbow', 'Swamp Drain Left', 'Swamp Drain Right', 'Swamp Flooded Room', 'Swamp Flooded Spot', 'Swamp Basement Shallows', 'Swamp Waterfall Room', - 'Swamp Refill', 'Swamp Behind Waterfall', 'Swamp C', 'Swamp Waterway', 'Swamp I', 'Swamp T', 'Swamp Boss' + 'Swamp Refill', 'Swamp Behind Waterfall', 'Swamp C', 'Swamp Waterway', 'Swamp I', 'Swamp T', 'Swamp Boss', + 'Swamp Portal' ] skull_regions = [ @@ -231,7 +235,8 @@ skull_regions = [ 'Skull Pot Prison', 'Skull Compass Room', 'Skull Left Drop', 'Skull 2 East Lobby', 'Skull Big Key', 'Skull Lone Pot', 'Skull Small Hall', 'Skull Back Drop', 'Skull 2 West Lobby', 'Skull X Room', 'Skull 3 Lobby', 'Skull East Bridge', 'Skull West Bridge Nook', 'Skull Star Pits', 'Skull Torch Room', 'Skull Vines', - 'Skull Spike Corner', 'Skull Final Drop', 'Skull Boss' + 'Skull Spike Corner', 'Skull Final Drop', 'Skull Boss', 'Skull 1 Portal', 'Skull 2 East Portal', + 'Skull 2 West Portal', 'Skull 3 Portal' ] thieves_regions = [ @@ -242,7 +247,7 @@ thieves_regions = [ '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 Blind's Cell Interior", 'Thieves Conveyor Bridge', 'Thieves Conveyor Block', - 'Thieves Big Chest Room', 'Thieves Trap' + 'Thieves Big Chest Room', 'Thieves Trap', 'Thieves Town Portal' ] ice_regions = [ @@ -253,7 +258,8 @@ ice_regions = [ 'Ice Tongue Pull', 'Ice Freezors', 'Ice Freezors Ledge', 'Ice Tall Hint', 'Ice Hookshot Ledge', 'Ice Hookshot Balcony', 'Ice Spikeball', 'Ice Lonely Freezor', 'Iced T', 'Ice Catwalk', 'Ice Many Pots', 'Ice Crystal Right', 'Ice Crystal Left', 'Ice Crystal Block', 'Ice Big Chest View', 'Ice Big Chest Landing', - 'Ice Backwards Room', 'Ice Anti-Fairy', 'Ice Switch Room', 'Ice Refill', 'Ice Fairy', 'Ice Antechamber', 'Ice Boss' + 'Ice Backwards Room', 'Ice Anti-Fairy', 'Ice Switch Room', 'Ice Refill', 'Ice Fairy', 'Ice Antechamber', 'Ice Boss', + 'Ice Portal' ] mire_regions = [ @@ -267,7 +273,7 @@ mire_regions = [ 'Mire Torches Top', 'Mire Torches Bottom', 'Mire Attic Hint', 'Mire Dark Shooters', 'Mire Key Rupees', 'Mire Block X', 'Mire Tall Dark and Roomy', 'Mire Crystal Right', 'Mire Crystal Mid', 'Mire Crystal Left', 'Mire Crystal Top', 'Mire Shooter Rupees', 'Mire Falling Foes', 'Mire Firesnake Skip', 'Mire Antechamber', - 'Mire Boss' + 'Mire Boss', 'Mire Portal' ] tr_regions = [ @@ -276,7 +282,8 @@ tr_regions = [ 'TR Lava Island', 'TR Lava Escape', 'TR Pokey 2', 'TR Twin Pokeys', 'TR Hallway', 'TR Dodgers', 'TR Big View', 'TR Big Chest', 'TR Big Chest Entrance', 'TR Lazy Eyes', 'TR Dash Room', 'TR Tongue Pull', 'TR Rupees', 'TR Crystaroller', 'TR Dark Ride', 'TR Dash Bridge', 'TR Eye Bridge', 'TR Crystal Maze', 'TR Crystal Maze End', - 'TR Final Abyss', 'TR Boss' + 'TR Final Abyss', 'TR Boss', 'Turtle Rock Main Portal', 'Turtle Rock Lazy Eyes Portal', 'Turtle Rock Chest Portal', + 'Turtle Rock Eye Bridge Portal' ] gt_regions = [ @@ -296,7 +303,7 @@ gt_regions = [ 'GT Dashing Bridge', 'GT Wizzrobes 2', 'GT Conveyor Bridge', 'GT Torch Cross', 'GT Staredown', 'GT Falling Torches', 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', 'GT Frozen Over', - 'GT Brightly Lit Hall', 'GT Agahnim 2' + 'GT Brightly Lit Hall', 'GT Agahnim 2', 'Ganons Tower Portal' ] diff --git a/EntranceShuffle.py b/EntranceShuffle.py index f51e79aa..710767f6 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -1063,7 +1063,7 @@ def link_entrances(world, player): raise NotImplementedError('Shuffling not supported yet') # check for swamp palace fix - if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Placeholder': + if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Portal': world.swamp_patch_required[player] = True # check for potion shop location @@ -1075,7 +1075,7 @@ def link_entrances(world, player): world.ganon_at_pyramid[player] = False # check for Ganon's Tower location - if world.get_entrance('Ganons Tower', player).connected_region.name != 'Ganons Tower Placeholder': + if world.get_entrance('Ganons Tower', player).connected_region.name != 'Ganons Tower Portal': world.ganonstower_vanilla[player] = False def link_inverted_entrances(world, player): @@ -3177,7 +3177,7 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Two Brothers House Exit (East)', 'Light World'), ('Two Brothers House Exit (West)', 'Maze Race Ledge'), - ('Sanctuary', 'Sanctuary Placeholder'), + ('Sanctuary', 'Sanctuary Portal'), ('Sanctuary Grave', 'Sewer Drop'), ('Sanctuary Exit', 'Light World'), @@ -3412,114 +3412,114 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Inverted Pyramid Entrance', 'Bottom of Pyramid')] # non shuffled dungeons -default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Placeholder'), - ('Desert Palace Entrance (West)', 'Desert West Placeholder'), - ('Desert Palace Entrance (North)', 'Desert Back Placeholder'), - ('Desert Palace Entrance (East)', 'Desert East Placeholder'), +default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), + ('Desert Palace Entrance (West)', 'Desert West Portal'), + ('Desert Palace Entrance (North)', 'Desert Back Portal'), + ('Desert Palace Entrance (East)', 'Desert East Portal'), ('Desert Palace Exit (South)', 'Desert Palace Stairs'), ('Desert Palace Exit (West)', 'Desert Ledge'), ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Placeholder'), + ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), - ('Tower of Hera', 'Hera Placeholder'), + ('Tower of Hera', 'Hera Portal'), ('Tower of Hera Exit', 'Death Mountain (Top)'), - ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Placeholder'), - ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Placeholder'), - ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Placeholder'), + ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), + ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - ('Agahnims Tower', 'Agahnims Tower Placeholder'), + ('Agahnims Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), - ('Thieves Town', 'Thieves Town Placeholder'), + ('Thieves Town', 'Thieves Town Portal'), ('Thieves Town Exit', 'West Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), - ('Skull Woods First Section Door', 'Skull 1 Placeholder'), + ('Skull Woods First Section Door', 'Skull 1 Portal'), ('Skull Woods First Section Exit', 'Skull Woods Forest'), ('Skull Woods Second Section Hole', 'Skull Back Drop'), - ('Skull Woods Second Section Door (East)', 'Skull 2 East Placeholder'), - ('Skull Woods Second Section Door (West)', 'Skull 2 West Placeholder'), + ('Skull Woods Second Section Door (East)', 'Skull 2 East Portal'), + ('Skull Woods Second Section Door (West)', 'Skull 2 West Portal'), ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), - ('Skull Woods Final Section', 'Skull 3 Placeholder'), + ('Skull Woods Final Section', 'Skull 3 Portal'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), - ('Ice Palace', 'Ice Placeholder'), + ('Ice Palace', 'Ice Portal'), ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), - ('Misery Mire', 'Mire Placeholder'), + ('Misery Mire', 'Mire Portal'), ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'Palace of Darkness Placeholder'), + ('Palace of Darkness', 'Palace of Darkness Portal'), ('Palace of Darkness Exit', 'East Dark World'), - ('Swamp Palace', 'Swamp Placeholder'), # requires additional patch for flooding moat if moved + ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved ('Swamp Palace Exit', 'South Dark World'), - ('Turtle Rock', 'Turtle Rock Main Placeholder'), + ('Turtle Rock', 'Turtle Rock Main Portal'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Placeholder'), - ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Placeholder'), + ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), + ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Placeholder'), + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), - ('Ganons Tower', 'Ganons Tower Placeholder'), + ('Ganons Tower', 'Ganons Tower Portal'), ('Ganons Tower Exit', 'Dark Death Mountain (Top)') ] -inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Main Lobby'), - ('Desert Palace Entrance (West)', 'Desert West Lobby'), - ('Desert Palace Entrance (North)', 'Desert Back Lobby'), - ('Desert Palace Entrance (East)', 'Desert East Lobby'), +inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), + ('Desert Palace Entrance (West)', 'Desert West Portal'), + ('Desert Palace Entrance (North)', 'Desert Back Portal'), + ('Desert Palace Entrance (East)', 'Desert East Portal'), ('Desert Palace Exit (South)', 'Desert Palace Stairs'), ('Desert Palace Exit (West)', 'Desert Ledge'), ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Lobby'), + ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), - ('Tower of Hera', 'Hera Lobby'), + ('Tower of Hera', 'Hera Portal'), ('Tower of Hera Exit', 'Death Mountain (Top)'), - ('Hyrule Castle Entrance (South)', 'Hyrule Castle Lobby'), - ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Lobby'), - ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Lobby'), + ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), + ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), ('Hyrule Castle Exit (South)', 'Light World'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - ('Thieves Town', 'Thieves Lobby'), + ('Thieves Town', 'Thieves Town Portal'), ('Thieves Town Exit', 'West Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), - ('Skull Woods First Section Door', 'Skull 1 Lobby'), + ('Skull Woods First Section Door', 'Skull 1 Portal'), ('Skull Woods First Section Exit', 'Skull Woods Forest'), ('Skull Woods Second Section Hole', 'Skull Back Drop'), - ('Skull Woods Second Section Door (East)', 'Skull 2 East Lobby'), - ('Skull Woods Second Section Door (West)', 'Skull 2 West Lobby'), + ('Skull Woods Second Section Door (East)', 'Skull 2 East Portal'), + ('Skull Woods Second Section Door (West)', 'Skull 2 West Portal'), ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), - ('Skull Woods Final Section', 'Skull 3 Lobby'), + ('Skull Woods Final Section', 'Skull 3 Portal'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), - ('Ice Palace', 'Ice Lobby'), - ('Misery Mire', 'Mire Lobby'), + ('Ice Palace', 'Ice Portal'), + ('Misery Mire', 'Mire Portal'), ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'PoD Lobby'), + ('Palace of Darkness', 'Palace of Darkness Portal'), ('Palace of Darkness Exit', 'East Dark World'), - ('Swamp Palace', 'Swamp Lobby'), # requires additional patch for flooding moat if moved + ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved ('Swamp Palace Exit', 'South Dark World'), - ('Turtle Rock', 'TR Main Lobby'), + ('Turtle Rock', 'Turtle Rock Main Portal'), ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge (West)', 'TR Lazy Eyes'), - ('Dark Death Mountain Ledge (East)', 'TR Big Chest Entrance'), + ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), + ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'TR Eye Bridge'), - ('Inverted Ganons Tower', 'GT Lobby'), + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), + ('Inverted Ganons Tower', 'Ganons Tower Portal'), ('Inverted Ganons Tower Exit', 'Hyrule Castle Ledge'), - ('Inverted Agahnims Tower', 'Tower Lobby'), + ('Inverted Agahnims Tower', 'Agahnims Tower Portal'), ('Inverted Agahnims Tower Exit', 'Dark Death Mountain'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), ('Ice Palace Exit', 'Dark Lake Hylia') diff --git a/Main.py b/Main.py index fa8b8bdf..59c61e7e 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, fill_specific_items from Utils import output_path, parse_player_names -__version__ = '0.2.0.12u' +__version__ = '0.2.0.13u' class EnemizerError(RuntimeError): pass diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 97de2d51..13e3f358 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -67,7 +67,7 @@ Redesign of Keysanity Menu complete for crossed dungeon and moved out of experim * 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. + many chests are left in the dungeon. If -keydropshuffle is off, this does not count key drop. If on, it does. ### Experimental features @@ -80,6 +80,13 @@ Redesign of Keysanity Menu complete for crossed dungeon and moved out of experim # Bug Fixes +* 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 @@ -91,7 +98,7 @@ Redesign of Keysanity Menu complete for crossed dungeon and moved out of experim * Fix output path setting in settings.json * Fix trock entrances when intensity <= 2 * 2.0.10u - * Fix POD, TR, GT and SKULL 3 entrance if sanc ends up in that dungeon in crossed ER+ + * 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 diff --git a/Regions.py b/Regions.py index 7b895891..fb991200 100644 --- a/Regions.py +++ b/Regions.py @@ -204,31 +204,31 @@ def create_dungeon_regions(world, player): std_flag = world.mode[player] == 'standard' inv_flag = world.mode[player] == 'inverted' world.regions += [ - create_dungeon_region(player, 'Sanctuary Placeholder', 'Twilight Zone', None, ['Sanctuary Exit']), - create_dungeon_region(player, 'Hyrule Castle West Placeholder', 'Twilight Zone', None, ['Hyrule Castle Exit (West)']), - create_dungeon_region(player, 'Hyrule Castle South Placeholder', 'Twilight Zone', None, ['Hyrule Castle Exit (South)']), - create_dungeon_region(player, 'Hyrule Castle East Placeholder', 'Twilight Zone', None, ['Hyrule Castle Exit (East)']), - create_dungeon_region(player, 'Eastern Placeholder', 'Twilight Zone', None, ['Eastern Palace Exit']), - create_dungeon_region(player, 'Desert West Placeholder', 'Twilight Zone', None, ['Desert Palace Exit (West)']), - create_dungeon_region(player, 'Desert South Placeholder', 'Twilight Zone', None, ['Desert Palace Exit (South)']), - create_dungeon_region(player, 'Desert East Placeholder', 'Twilight Zone', None, ['Desert Palace Exit (East)']), - create_dungeon_region(player, 'Desert Back Placeholder', 'Twilight Zone', None, ['Desert Palace Exit (North)']), - create_dungeon_region(player, 'Hera Placeholder', 'Twilight Zone', None, ['Tower of Hera Exit']), - create_dungeon_region(player, 'Agahnims Tower Placeholder', 'Twilight Zone', None, [inv_flag and 'Inverted Agahnims Tower Exit' or 'Agahnims Tower Exit']), - create_dungeon_region(player, 'Palace of Darkness Placeholder', 'Twilight Zone', None, ['Palace of Darkness Exit']), - create_dungeon_region(player, 'Swamp Placeholder', 'Twilight Zone', None, ['Swamp Palace Exit']), - create_dungeon_region(player, 'Skull 1 Placeholder', 'Twilight Zone', None, ['Skull Woods First Section Exit']), - create_dungeon_region(player, 'Skull 2 East Placeholder', 'Twilight Zone', None, ['Skull Woods Second Section Exit (East)']), - create_dungeon_region(player, 'Skull 2 West Placeholder', 'Twilight Zone', None, ['Skull Woods Second Section Exit (West)']), - create_dungeon_region(player, 'Skull 3 Placeholder', 'Twilight Zone', None, ['Skull Woods Final Section Exit']), - create_dungeon_region(player, 'Thieves Town Placeholder', 'Twilight Zone', None, ['Thieves Town Exit']), - create_dungeon_region(player, 'Ice Placeholder', 'Twilight Zone', None, ['Ice Palace Exit']), - create_dungeon_region(player, 'Mire Placeholder', 'Twilight Zone', None, ['Misery Mire Exit']), - create_dungeon_region(player, 'Turtle Rock Main Placeholder', 'Twilight Zone', None, ['Turtle Rock Exit (Front)']), - create_dungeon_region(player, 'Turtle Rock Lazy Eyes Placeholder', 'Twilight Zone', None, ['Turtle Rock Ledge Exit (West)']), - create_dungeon_region(player, 'Turtle Rock Chest Placeholder', 'Twilight Zone', None, ['Turtle Rock Ledge Exit (East)']), - create_dungeon_region(player, 'Turtle Rock Eye Bridge Placeholder', 'Twilight Zone', None, ['Turtle Rock Isolated Ledge Exit']), - create_dungeon_region(player, 'Ganons Tower Placeholder', 'Twilight Zone', None, [inv_flag and 'Inverted Ganons Tower Exit' or 'Ganons Tower Exit']), + create_dungeon_region(player, 'Sanctuary Portal', 'Hyrule Castle', None, ['Sanctuary Exit', 'Enter HC (Sanc)']), + create_dungeon_region(player, 'Hyrule Castle West Portal', 'Hyrule Castle', None, ['Hyrule Castle Exit (West)', 'Enter HC (West)']), + create_dungeon_region(player, 'Hyrule Castle South Portal', 'Hyrule Castle', None, ['Hyrule Castle Exit (South)', 'Enter HC (South)']), + create_dungeon_region(player, 'Hyrule Castle East Portal', 'Hyrule Castle', None, ['Hyrule Castle Exit (East)', 'Enter HC (East)']), + create_dungeon_region(player, 'Eastern Portal', 'Eastern Palace', None, ['Eastern Palace Exit', 'Enter Eastern Palace']), + create_dungeon_region(player, 'Desert West Portal', 'Desert Palace', None, ['Desert Palace Exit (West)', 'Enter Desert (West)']), + create_dungeon_region(player, 'Desert South Portal', 'Desert Palace', None, ['Desert Palace Exit (South)', 'Enter Desert (South)']), + create_dungeon_region(player, 'Desert East Portal', 'Desert Palace', None, ['Desert Palace Exit (East)', 'Enter Desert (East)']), + create_dungeon_region(player, 'Desert Back Portal', 'Desert Palace', None, ['Desert Palace Exit (North)', 'Enter Desert (North)']), + create_dungeon_region(player, 'Hera Portal', 'Tower of Hera', None, ['Tower of Hera Exit', 'Enter Hera']), + create_dungeon_region(player, 'Agahnims Tower Portal', 'Castle Tower', None, [inv_flag and 'Inverted Agahnims Tower Exit' or 'Agahnims Tower Exit', 'Enter Agahnims Tower']), + create_dungeon_region(player, 'Palace of Darkness Portal', 'Palace of Darkness', None, ['Palace of Darkness Exit', 'Enter Palace of Darkness']), + create_dungeon_region(player, 'Swamp Portal', 'Swamp Palace', None, ['Swamp Palace Exit', 'Enter Swamp']), + create_dungeon_region(player, 'Skull 1 Portal', 'Skull Woods', None, ['Skull Woods First Section Exit', 'Enter Skull Woods 1']), + create_dungeon_region(player, 'Skull 2 East Portal', 'Skull Woods', None, ['Skull Woods Second Section Exit (East)', 'Enter Skull Woods 2 (East)']), + create_dungeon_region(player, 'Skull 2 West Portal', 'Skull Woods', None, ['Skull Woods Second Section Exit (West)', 'Enter Skull Woods 2 (West)']), + create_dungeon_region(player, 'Skull 3 Portal', 'Skull Woods', None, ['Skull Woods Final Section Exit', 'Enter Skull Woods 3']), + create_dungeon_region(player, 'Thieves Town Portal', "Thieves' Town", None, ['Thieves Town Exit', 'Enter Thieves Town']), + create_dungeon_region(player, 'Ice Portal', 'Ice Palace', None, ['Ice Palace Exit', 'Enter Ice Palace']), + create_dungeon_region(player, 'Mire Portal', 'Misery Mire', None, ['Misery Mire Exit', 'Enter Misery Mire']), + create_dungeon_region(player, 'Turtle Rock Main Portal', 'Turtle Rock', None, ['Turtle Rock Exit (Front)', 'Enter Turtle Rock (Main)']), + create_dungeon_region(player, 'Turtle Rock Lazy Eyes Portal', 'Turtle Rock', None, ['Turtle Rock Ledge Exit (West)', 'Enter Turtle Rock (Lazy Eyes)']), + create_dungeon_region(player, 'Turtle Rock Chest Portal', 'Turtle Rock', None, ['Turtle Rock Ledge Exit (East)', 'Enter Turtle Rock (Chest)']), + create_dungeon_region(player, 'Turtle Rock Eye Bridge Portal', 'Turtle Rock', None, ['Turtle Rock Isolated Ledge Exit', 'Enter Turtle Rock (Laser Bridge)']), + create_dungeon_region(player, 'Ganons Tower Portal', "Ganon's Tower", None, [inv_flag and 'Inverted Ganons Tower Exit' or 'Ganons Tower Exit', 'Enter Ganons Tower']), create_dungeon_region(player, 'Hyrule Castle Lobby', 'Hyrule Castle', None, ['Hyrule Castle Lobby W', 'Hyrule Castle Lobby E', 'Hyrule Castle Lobby WN', 'Hyrule Castle Lobby North Stairs', 'Hyrule Castle Lobby S']), diff --git a/Rom.py b/Rom.py index 8073b8e8..2737c7c4 100644 --- a/Rom.py +++ b/Rom.py @@ -11,7 +11,7 @@ import subprocess import bps.apply import bps.io -from BaseClasses import CollectionState, ShopType, Region, Location, DoorType, RegionType +from BaseClasses import CollectionState, ShopType, Region, Location, Door, DoorType, RegionType from DoorShuffle import compass_data, DROptions, boss_indicator from Dungeons import dungeon_music_addresses from KeyDoorShuffle import count_locations_exclude_logic @@ -26,7 +26,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '87fb1ec80d48487a84eac3a0a9bf9e04' +RANDOMIZERBASEHASH = '55b2f851e5d643e1e72befc631ea3c6d' class JsonRom(object): @@ -670,8 +670,9 @@ def patch_rom(world, rom, player, team, enemized): if world.doorShuffle[player] == 'basic': rom.write_byte(0x138002, 1) for door in world.doors: - if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs, - DoorType.Open, DoorType.StraightStairs]: + 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]: 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)) @@ -715,14 +716,16 @@ def patch_rom(world, rom, player, team, enemized): world.force_fix[player]['sw'] |= world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla' # fix exits, if not fixed during exit patching - if world.force_fix[player]['sw']: + if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla': write_int16(rom, 0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8) + elif world.force_fix[player]['sw']: + write_int16(rom, 0x15DB5 + world.force_fix[player]['sw'].exit_offset, 0x00F8) if world.force_fix[player]['pod']: - write_int16(rom, 0x15DB5 + 2 * exit_ids['Palace of Darkness Exit'][1], 0x0640) + write_int16(rom, 0x15DB5 + world.force_fix[player]['pod'].exit_offset, 0x0640) if world.force_fix[player]['tr']: - write_int16(rom, 0x15DB5 + 2 * exit_ids['Turtle Rock Exit (Front)'][1], 0x0134) + write_int16(rom, 0x15DB5 + world.force_fix[player]['tr'].exit_offset, 0x0134) if world.force_fix[player]['gt']: - write_int16(rom, 0x15DB5 + 2 * exit_ids['Ganons Tower Exit'][1], 0x00A4) + write_int16(rom, 0x15DB5 + world.force_fix[player]['gt'].exit_offset, 0x00A4) write_custom_shops(rom, world, player) @@ -1294,8 +1297,7 @@ def patch_rom(world, rom, player, team, enemized): x = idx*2 room_idx = portal.door.roomIndex room = world.get_room(room_idx, player) - rom.write_byte(0x13f0f0+x, room_idx & 0xff) - rom.write_byte(0x13f0f1+x, (room_idx >> 8) & 0xff) + write_int16(rom, 0x13f0f0+x, room_idx) rom.write_byte(0x13f0f6+x, room.position(portal.door).value) rom.write_byte(0x13f0f7+x, room.kind(portal.door).value) diff --git a/Rules.py b/Rules.py index bfae85ed..118b3bb2 100644 --- a/Rules.py +++ b/Rules.py @@ -190,6 +190,9 @@ def global_rules(world, player): set_rule(world.get_entrance('Swamp Trench 1 Approach Dry', player), lambda state: not state.has('Trench 1 Filled', player)) set_rule(world.get_entrance('Swamp Trench 1 Key Ledge Dry', player), lambda state: not state.has('Trench 1 Filled', player)) set_rule(world.get_entrance('Swamp Trench 1 Departure Dry', player), lambda state: not state.has('Trench 1 Filled', player)) + # these two are here so that, if they flood the area before finding flippers, nothing behind there can lock out the flippers + set_rule(world.get_entrance('Swamp Trench 1 Nexus Approach', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Swamp Trench 1 Nexus Key', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Swamp Trench 1 Approach Key', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player)) set_rule(world.get_entrance('Swamp Trench 1 Approach Swim Depart', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player)) set_rule(world.get_entrance('Swamp Trench 1 Key Approach', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player)) @@ -251,7 +254,8 @@ def global_rules(world, player): set_rule(world.get_location('Ice Palace - Freezor Chest', player), lambda state: state.can_melt_things(player)) set_rule(world.get_entrance('Ice Hookshot Ledge Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Ice Hookshot Balcony Path', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Ice Switch Room SE', player), lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player)) + if not world.get_door('Ice Switch Room SE', player).entranceFlag: + set_rule(world.get_entrance('Ice Switch Room SE', player), lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player)) set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Prize', player)) @@ -294,7 +298,8 @@ def global_rules(world, player): set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('GT Conveyor Cross WN', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('GT Conveyor Cross EN', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) + if not world.get_door('GT Speed Torch SE', player).entranceFlag: + set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('GT Hookshot East-North Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Hookshot South-East Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Hookshot South-North Path', player), lambda state: state.has('Hookshot', player)) @@ -316,7 +321,8 @@ def global_rules(world, player): set_rule(world.get_entrance('GT Gauntlet 2 EN', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('GT Gauntlet 2 SW', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('GT Gauntlet 3 NW', player), lambda state: state.can_kill_most_things(player)) - set_rule(world.get_entrance('GT Gauntlet 3 SW', player), lambda state: state.can_kill_most_things(player)) + if not world.get_door('GT Gauntlet 3 SW', player).entranceFlag: + set_rule(world.get_entrance('GT Gauntlet 3 SW', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('GT Gauntlet 4 NW', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('GT Gauntlet 4 SW', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('GT Gauntlet 5 NW', player), lambda state: state.can_kill_most_things(player)) diff --git a/asm/hudadditions.asm b/asm/hudadditions.asm index 29da1e8c..f0ed773e 100644 --- a/asm/hudadditions.asm +++ b/asm/hudadditions.asm @@ -95,7 +95,7 @@ DrHudDungeonItemsAdditions: + stx $00 txa : lsr : tax lda.w #$24f5 : sta $1644, y - lda.l GenericKeys : bne + + lda.l GenericKeys : and #$00FF : bne + lda.l $7ef37c, x : and #$00FF : beq + jsr ConvertToDisplay2 : sta $1644, y + iny #2 : lda.w #$24f5 : sta $1644, y diff --git a/data/base2current.bps b/data/base2current.bps index 165e57dd..2b70fcc0 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ