Merge pull request #110 from compiling/multiworld
OWG mandatory exit rules
This commit is contained in:
		
						commit
						35933b88c4
					
				| 
						 | 
				
			
			@ -1910,9 +1910,7 @@ def connect_random(world, exitlist, targetlist, player, two_way=False):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def connect_mandatory_exits(world, entrances, caves, must_be_exits, player):
 | 
			
		||||
    """This works inplace"""
 | 
			
		||||
    random.shuffle(entrances)
 | 
			
		||||
    random.shuffle(caves)
 | 
			
		||||
 | 
			
		||||
    # Keeps track of entrances that cannot be used to access each exit / cave
 | 
			
		||||
    if world.mode[player] == 'inverted':
 | 
			
		||||
        invalid_connections = Inverted_Must_Exit_Invalid_Connections.copy()
 | 
			
		||||
| 
						 | 
				
			
			@ -1920,6 +1918,18 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player):
 | 
			
		|||
        invalid_connections = Must_Exit_Invalid_Connections.copy()
 | 
			
		||||
    invalid_cave_connections = defaultdict(set)
 | 
			
		||||
 | 
			
		||||
    if world.logic[player] in ['owglitches', 'nologic']:
 | 
			
		||||
        import OverworldGlitchRules
 | 
			
		||||
        for entrance in OverworldGlitchRules.get_non_mandatory_exits(world.mode[player] == 'inverted'):
 | 
			
		||||
            invalid_connections[entrance] = set()
 | 
			
		||||
            if entrance in must_be_exits:
 | 
			
		||||
                must_be_exits.remove(entrance)
 | 
			
		||||
                entrances.append(entrance)
 | 
			
		||||
 | 
			
		||||
    """This works inplace"""
 | 
			
		||||
    random.shuffle(entrances)
 | 
			
		||||
    random.shuffle(caves)
 | 
			
		||||
 | 
			
		||||
    # Handle inverted Aga Tower - if it depends on connections, then so does Hyrule Castle Ledge
 | 
			
		||||
    if world.mode[player] == 'inverted':
 | 
			
		||||
        for entrance in invalid_connections:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,6 +92,37 @@ def get_superbunny_accessible_locations():
 | 
			
		|||
        yield location
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_non_mandatory_exits(inverted):
 | 
			
		||||
    """
 | 
			
		||||
    Entrances that can be reached with full equipment using overworld glitches and don't need to be an exit.
 | 
			
		||||
    The following are still be mandatory exits:
 | 
			
		||||
 | 
			
		||||
    Open:
 | 
			
		||||
    Turtle Rock Isolated Ledge Entrance
 | 
			
		||||
    Skull Woods Second Section Door (West) (or Skull Woods Final Section)
 | 
			
		||||
 | 
			
		||||
    Inverted:
 | 
			
		||||
    Two Brothers House (West)
 | 
			
		||||
    Desert Palace Entrance (East)
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    yield 'Bumper Cave (Top)'
 | 
			
		||||
    yield 'Death Mountain Return Cave (West)'
 | 
			
		||||
    yield 'Hookshot Cave Back Entrance'
 | 
			
		||||
 | 
			
		||||
    if inverted:
 | 
			
		||||
        yield 'Desert Palace Entrance (North)'
 | 
			
		||||
        yield 'Desert Palace Entrance (West)'
 | 
			
		||||
        yield 'Inverted Ganons Tower'
 | 
			
		||||
        yield 'Hyrule Castle Entrance (West)'
 | 
			
		||||
        yield 'Hyrule Castle Entrance (East)'
 | 
			
		||||
    else:
 | 
			
		||||
        yield 'Dark Death Mountain Ledge (West)'
 | 
			
		||||
        yield 'Dark Death Mountain Ledge (East)'
 | 
			
		||||
        yield 'Mimic Cave'
 | 
			
		||||
        yield 'Desert Palace Entrance (East)'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_boots_clip_exits_lw(inverted = False):
 | 
			
		||||
    """
 | 
			
		||||
    Special Light World region exits that require boots clips.
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +151,7 @@ def get_boots_clip_exits_lw(inverted = False):
 | 
			
		|||
        yield ('Cave 45 Clip Spot', 'Light World', 'Cave 45 Ledge')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_boots_clip_exits_dw(inverted = False):
 | 
			
		||||
def get_boots_clip_exits_dw(inverted, player):
 | 
			
		||||
    """
 | 
			
		||||
    Special Dark World region exits that require boots clips.
 | 
			
		||||
    """
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +170,7 @@ def get_boots_clip_exits_dw(inverted = False):
 | 
			
		|||
        yield ('Ganons Tower Ascent', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (Top)')  # This only gets you to the GT entrance
 | 
			
		||||
        yield ('Dark Death Mountain Glitched Bridge', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (Top)')
 | 
			
		||||
        yield ('Turtle Rock (Top) Clip Spot', 'Dark Death Mountain (Top)', 'Turtle Rock (Top)')
 | 
			
		||||
        yield ('Ice Palace Clip', 'South Dark World', 'Dark Lake Hylia Central Island', lambda state: state.can_boots_clip_dw(player) and state.has('Flippers', player))
 | 
			
		||||
    else:
 | 
			
		||||
        yield ('Dark Desert Teleporter Clip Spot', 'Dark Desert', 'Dark Desert Ledge')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -152,26 +184,33 @@ def get_glitched_speed_drops_dw(inverted = False):
 | 
			
		|||
 | 
			
		||||
def get_mirror_clip_spots_dw():
 | 
			
		||||
    """
 | 
			
		||||
    Mirror shenanigans that are in logic even if the player is a bunny.
 | 
			
		||||
    Out of bounds transitions using the mirror
 | 
			
		||||
    """
 | 
			
		||||
    yield ('Dark Death Mountain Offset Mirror', 'Dark Death Mountain (West Bottom)', 'East Dark World')
 | 
			
		||||
    yield ('Dark Death Mountain Bunny Descent Mirror Spot', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain Bunny Descent Area')
 | 
			
		||||
    yield ('West Dark World Bunny Descent', 'Dark Death Mountain Bunny Descent Area', 'West Dark World')
 | 
			
		||||
    yield ('Dark Death Mountain (East Bottom) Jump', 'Dark Death Mountain Bunny Descent Area', 'Dark Death Mountain (East Bottom)')
 | 
			
		||||
    yield ('Desert East Mirror Clip', 'Dark Desert', 'Desert Palace Lone Stairs')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_mirror_clip_spots_lw():
 | 
			
		||||
def get_mirror_offset_spots_dw():
 | 
			
		||||
    """
 | 
			
		||||
    Inverted mirror shenanigans in logic even if the player is a bunny.
 | 
			
		||||
    Mirror shenanigans placing a mirror portal with a broken camera
 | 
			
		||||
    """
 | 
			
		||||
    yield ('Death Mountain Bunny Descent Mirror Spot', 'Death Mountain', 'Death Mountain Bunny Descent Area')
 | 
			
		||||
    yield ('Light World Bunny Descent', 'Death Mountain Bunny Descent Area', 'Light World')
 | 
			
		||||
    yield ('East Death Mountain (Bottom) Jump', 'Death Mountain Bunny Descent Area', 'East Death Mountain (Bottom)')
 | 
			
		||||
    yield ('Dark Death Mountain Offset Mirror', 'Dark Death Mountain (West Bottom)', 'East Dark World')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_mirror_offset_spots_lw(player):
 | 
			
		||||
    """
 | 
			
		||||
    Mirror shenanigans placing a mirror portal with a broken camera
 | 
			
		||||
    """
 | 
			
		||||
    yield ('Death Mountain Offset Mirror', 'Death Mountain', 'Light World')
 | 
			
		||||
    yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'Death Mountain', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_invalid_bunny_revival_dungeons():
 | 
			
		||||
    """
 | 
			
		||||
    Dungeon regions that can't be bunny revived from.
 | 
			
		||||
    Dungeon regions that can't be bunny revived from without superbunny state.
 | 
			
		||||
    """
 | 
			
		||||
    yield 'Tower of Hera (Bottom)'
 | 
			
		||||
    yield 'Swamp Palace (Entrance)'
 | 
			
		||||
| 
						 | 
				
			
			@ -183,10 +222,7 @@ def overworld_glitches_rules(world, player):
 | 
			
		|||
 | 
			
		||||
    # Boots-accessible locations.
 | 
			
		||||
    create_owg_connections(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'), lambda state: state.can_boots_clip_lw(player))
 | 
			
		||||
    create_owg_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted'), lambda state: state.can_boots_clip_dw(player))
 | 
			
		||||
 | 
			
		||||
    if world.mode[player] != 'inverted':
 | 
			
		||||
        create_owg_connections(player, world, [('Ice Palace Clip', 'South Dark World', 'Dark Lake Hylia Central Island')], lambda state: state.can_boots_clip_dw(player) and state.has('Flippers', player))
 | 
			
		||||
    create_owg_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player), lambda state: state.can_boots_clip_dw(player))
 | 
			
		||||
 | 
			
		||||
    # Glitched speed drops.
 | 
			
		||||
    create_owg_connections(player, world, get_glitched_speed_drops_dw(world.mode[player] == 'inverted'), lambda state: state.can_get_glitched_speed_dw(player))
 | 
			
		||||
| 
						 | 
				
			
			@ -197,8 +233,9 @@ def overworld_glitches_rules(world, player):
 | 
			
		|||
    # Mirror clip spots.
 | 
			
		||||
    if world.mode[player] != 'inverted':
 | 
			
		||||
        create_owg_connections(player, world, get_mirror_clip_spots_dw(), lambda state: state.has_Mirror(player))
 | 
			
		||||
        create_owg_connections(player, world, get_mirror_offset_spots_dw(), lambda state: state.has_Mirror(player) and state.can_boots_clip_lw(player))
 | 
			
		||||
    else:
 | 
			
		||||
        create_owg_connections(player, world, get_mirror_clip_spots_lw(), lambda state: state.has_Mirror(player))
 | 
			
		||||
        create_owg_connections(player, world, get_mirror_offset_spots_lw(player), lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player))
 | 
			
		||||
 | 
			
		||||
    # Regions that require the boots and some other stuff.
 | 
			
		||||
    if world.mode[player] != 'inverted':
 | 
			
		||||
| 
						 | 
				
			
			@ -220,11 +257,12 @@ def add_alternate_rule(entrance, rule):
 | 
			
		|||
    entrance.access_rule = lambda state: old_rule(state) or rule(state)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_owg_connections(player, world, connections, rule):
 | 
			
		||||
    for entrance, parent_region, target_region in connections:
 | 
			
		||||
def create_owg_connections(player, world, connections, default_rule):
 | 
			
		||||
    for entrance, parent_region, target_region, *rule_override in connections:
 | 
			
		||||
        parent = world.get_region(parent_region, player)
 | 
			
		||||
        target = world.get_region(target_region, player)
 | 
			
		||||
        connection = Entrance(player, entrance, parent)
 | 
			
		||||
        parent.exits.append(connection)
 | 
			
		||||
        connection.connect(target)
 | 
			
		||||
        rule = rule_override[0] if len(rule_override) > 0 else default_rule
 | 
			
		||||
        connection.access_rule = rule
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,42 +81,44 @@ class TestDarkWorld(TestVanillaOWG):
 | 
			
		|||
 | 
			
		||||
            ["Pyramid", False, []],
 | 
			
		||||
            ["Pyramid", False, [], ['Beat Agahnim 1', 'Moon Pearl', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid", False, [], ['Beat Agahnim 1', 'Moon Pearl', 'Pegasus Boots', 'Flute', 'Lamp']],
 | 
			
		||||
            ["Pyramid", False, [], ['Beat Agahnim 1', 'Moon Pearl', 'Pegasus Boots']],
 | 
			
		||||
            ["Pyramid", True, ['Moon Pearl', 'Pegasus Boots']],
 | 
			
		||||
            ["Pyramid", True, ['Magic Mirror', 'Pegasus Boots']],
 | 
			
		||||
            ["Pyramid", True, ['Magic Mirror', 'Flute']],
 | 
			
		||||
            ["Pyramid", True, ['Magic Mirror', 'Progressive Glove', 'Lamp']],
 | 
			
		||||
            ["Pyramid", True, ['Beat Agahnim 1']],
 | 
			
		||||
            ["Pyramid", True, ['Moon Pearl', 'Progressive Glove', 'Hammer']],
 | 
			
		||||
            ["Pyramid", True, ['Moon Pearl', 'Progressive Glove', 'Progressive Glove', 'Flippers']],
 | 
			
		||||
 | 
			
		||||
            ["Pyramid Fairy - Left", False, []],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Pegasus Boots', 'Moon Pearl', 'Flute', 'Lamp']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Pegasus Boots', 'Moon Pearl', 'Beat Agahnim 1']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Pegasus Boots', 'Moon Pearl', 'Crystal 5']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Pegasus Boots', 'Moon Pearl', 'Crystal 6']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Magic Mirror', 'Crystal 5']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Magic Mirror', 'Crystal 6']],
 | 
			
		||||
            ["Pyramid Fairy - Left", False, [], ['Magic Mirror', 'Moon Pearl']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Magic Mirror', 'Pegasus Boots']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Flute', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Progressive Glove', 'Lamp', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Hammer']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Progressive Glove', 'Hammer']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Progressive Glove', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Hookshot', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Flippers', 'Hookshot', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Flute', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Left", True, ['Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Lamp', 'Magic Mirror']],
 | 
			
		||||
 | 
			
		||||
            ["Pyramid Fairy - Right", False, []],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Pegasus Boots', 'Moon Pearl', 'Flute', 'Lamp']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Pegasus Boots', 'Moon Pearl', 'Beat Agahnim 1']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Pegasus Boots', 'Moon Pearl', 'Crystal 5']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Pegasus Boots', 'Moon Pearl', 'Crystal 6']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Magic Mirror', 'Crystal 5']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Magic Mirror', 'Crystal 6']],
 | 
			
		||||
            ["Pyramid Fairy - Right", False, [], ['Magic Mirror', 'Moon Pearl']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Magic Mirror', 'Pegasus Boots']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Flute', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Progressive Glove', 'Lamp', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Hammer']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Progressive Glove', 'Hammer']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Progressive Glove', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Hookshot', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Moon Pearl', 'Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Flippers', 'Hookshot', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Flute', 'Magic Mirror']],
 | 
			
		||||
            ["Pyramid Fairy - Right", True, ['Crystal 5', 'Crystal 6', 'Beat Agahnim 1', 'Progressive Glove', 'Lamp', 'Magic Mirror']],
 | 
			
		||||
 | 
			
		||||
            ["Ganon", False, []],
 | 
			
		||||
            ["Ganon", False, [], ['Moon Pearl']],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue