From c09fab64f81c3016d3f7d01f4c79ee77343dde95 Mon Sep 17 00:00:00 2001 From: qadan Date: Fri, 3 Jan 2020 04:02:15 -0400 Subject: [PATCH 1/6] first pass at owg logic support --- EntranceRandomizer.py | 7 ++-- EntranceShuffle.py | 3 +- Gui.py | 2 +- InvertedRegions.py | 2 +- ItemList.py | 34 ++++++++++-------- Mystery.py | 6 ++-- Rom.py | 8 ++++- Rules.py | 84 ++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 122 insertions(+), 24 deletions(-) diff --git a/EntranceRandomizer.py b/EntranceRandomizer.py index 91fa5bfa..53476548 100755 --- a/EntranceRandomizer.py +++ b/EntranceRandomizer.py @@ -28,14 +28,17 @@ def parse_arguments(argv, no_defaults=False): parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) parser.add_argument('--create_spoiler', help='Output a Spoiler File', action='store_true') - parser.add_argument('--logic', default=defval('noglitches'), const='noglitches', nargs='?', choices=['noglitches', 'minorglitches', 'nologic'], + parser.add_argument('--logic', default=defval('noglitches'), const='noglitches', nargs='?', choices=['noglitches', 'minorglitches', 'owglitches', 'nologic'], help='''\ Select Enforcement of Item Requirements. (default: %(default)s) No Glitches: Minor Glitches: May require Fake Flippers, Bunny Revival and Dark Room Navigation. + Overworld Glitches: May require overworld glitches. Starts with + boots. No Logic: Distribute items without regard for - item requirements. + item requirements. Starts with + boots ''') parser.add_argument('--mode', default=defval('open'), const='open', nargs='?', choices=['standard', 'open', 'inverted'], help='''\ diff --git a/EntranceShuffle.py b/EntranceShuffle.py index a96811b8..49339ab2 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2987,7 +2987,8 @@ mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central ('Pyramid Drop', 'East Dark World') ] -inverted_mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), +inverted_mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), + ('Lake Hylia Island', 'Lake Hylia Island'), ('Zoras River', 'Zoras River'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), diff --git a/Gui.py b/Gui.py index b897866b..538afdbc 100755 --- a/Gui.py +++ b/Gui.py @@ -193,7 +193,7 @@ def guiMain(args=None): logicFrame = Frame(drowDownFrame) logicVar = StringVar() logicVar.set('noglitches') - logicOptionMenu = OptionMenu(logicFrame, logicVar, 'noglitches', 'minorglitches', 'nologic') + logicOptionMenu = OptionMenu(logicFrame, logicVar, 'noglitches', 'minorglitches', 'owglitches', 'nologic') logicOptionMenu.pack(side=RIGHT) logicLabel = Label(logicFrame, text='Game logic') logicLabel.pack(side=LEFT) diff --git a/InvertedRegions.py b/InvertedRegions.py index d0f0e8bc..e1915d39 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -9,7 +9,7 @@ def create_inverted_regions(world, player): ["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Kings Grave Outer Rocks', 'Dam', 'Inverted Big Bomb Shop', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', - 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', + 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', 'Lake Hylia Island', 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow', 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Light World River Drop', 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', diff --git a/ItemList.py b/ItemList.py index 19eb83e3..3db3f130 100644 --- a/ItemList.py +++ b/ItemList.py @@ -177,7 +177,7 @@ def generate_itempool(world, player): (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.customitemarray) world.rupoor_cost = min(world.customitemarray[69], 9999) else: - (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player]) + (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.logic[player]) for item in precollected_items: world.push_precollected(ItemFactory(item, player)) @@ -386,7 +386,7 @@ def set_up_shops(world, player): #special shop types -def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro): +def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, logic): pool = [] placed_items = {} precollected_items = [] @@ -403,6 +403,11 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r def want_progressives(): return random.choice([True, False]) if progressive == 'random' else progressive == 'on' + # provide boots to major glitch dependent seeds + if logic in ['owglitches', 'nologic']: + precollected_items.append('Pegasus Boots') + pool.remove('Pegasus Boots') + if want_progressives(): pool.extend(progressivegloves) else: @@ -685,19 +690,20 @@ def test(): for progressive in ['on', 'off']: for shuffle in ['full', 'insanity_legacy']: for retro in [True, False]: - out = get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro) - count = len(out[0]) + len(out[1]) + for logic in ['noglitches', 'owglitches']: + out = get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, logic) + count = len(out[0]) + len(out[1]) - correct_count = total_items_to_place - if goal == 'pedestal' and swords != 'vanilla': - # pedestal goals generate one extra item - correct_count += 1 - if retro: - correct_count += 28 - try: - assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro)) - except AssertionError as e: - print(e) + correct_count = total_items_to_place + if goal == 'pedestal' and swords != 'vanilla': + # pedestal goals generate one extra item + correct_count += 1 + if retro: + correct_count += 28 + try: + assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro)) + except AssertionError as e: + print(e) if __name__ == '__main__': test() diff --git a/Mystery.py b/Mystery.py index 06f57aca..2a79c990 100644 --- a/Mystery.py +++ b/Mystery.py @@ -114,10 +114,10 @@ def roll_settings(weights): ret = argparse.Namespace() glitches_required = get_choice('glitches_required') - if glitches_required not in ['none', 'no_logic']: - print("Only NMG and No Logic supported") + if glitches_required not in ['none', 'no_logic', 'overworld_glitches']: + print("Only NMG, OWG and No Logic supported") glitches_required = 'none' - ret.logic = {'none': 'noglitches', 'no_logic': 'nologic'}[glitches_required] + ret.logic = {'none': 'noglitches', 'no_logic': 'nologic', 'overworld_glitches': 'owglitches'}[glitches_required] item_placement = get_choice('item_placement') # not supported in ER diff --git a/Rom.py b/Rom.py index aa4c150a..79e85a1b 100644 --- a/Rom.py +++ b/Rom.py @@ -901,7 +901,7 @@ def patch_rom(world, player, rom, enemized): rom.write_byte(x, 0) # Zero the initial equipment array rom.write_byte(0x18302C, 0x18) # starting max health rom.write_byte(0x18302D, 0x18) # starting current health - rom.write_byte(0x183039, 0x68) # starting abilities, bit array + ability_flags = 0x68 # starting abilities, bit array; may be modified by precollected items for item in world.precollected_items: if item.player != player: @@ -911,9 +911,15 @@ def patch_rom(world, player, rom, enemized): rom.write_byte(0x183000+0x19, 0x01) rom.write_byte(0x0271A6+0x19, 0x01) rom.write_byte(0x180043, 0x01) # special starting sword byte + elif item.name == 'Pegasus Boots': + rom.write_byte(0x183015, 0x01) + ability_flags |= 0b00000100 else: raise RuntimeError("Unsupported pre-collected item: {}".format(item)) + # write abilities after ability flags have been determined + rom.write_byte(0x183039, ability_flags) + rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier rom.write_byte(0x2AF79, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both) diff --git a/Rules.py b/Rules.py index 5ce634d4..41015113 100644 --- a/Rules.py +++ b/Rules.py @@ -38,6 +38,8 @@ def set_rules(world, player): if world.logic[player] == 'noglitches': no_glitches_rules(world, player) + elif world.logic[player] == 'owglitches': + overworld_glitches_rules(world, player) elif world.logic[player] == 'minorglitches': logging.getLogger('').info('Minor Glitches may be buggy still. No guarantee for proper logic checks.') else: @@ -357,7 +359,6 @@ def default_rules(world, player): set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) # Caution: If king's grave is releaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Desert Palace Stairs', player), lambda state: state.has('Book of Mudora', player)) @@ -625,8 +626,10 @@ def no_glitches_rules(world, player): set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) else: + set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Zoras River', player), lambda state: state.has_Pearl(player) and (state.has('Flippers', player) or state.can_lift_rocks(player))) set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Lake Hylia Island', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) set_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) @@ -641,7 +644,10 @@ def no_glitches_rules(world, player): set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: False) # no glitches does not require block override set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) set_rule(world.get_entrance('Skull Woods First Section Bomb Jump', player), lambda state: False) + add_conditional_lamps(world, player) + +def add_conditional_lamps(world, player): # Light cones in standard depend on which world we actually are in, not which one the location would normally be # We add Lamp requirements only to those locations which lie in the dark world (or everything if open DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Bumper Cave (Top)', 'Hookshot Cave Back Entrance', 'Dark Death Mountain Ledge (East)', @@ -690,6 +696,82 @@ def no_glitches_rules(world, player): add_lamp_requirement(world.get_entrance('Throne Room', player), player) +def overworld_glitches_rules(world, player): + # spots that are immediately accessible + set_rule(world.get_entrance('Hobo Bridge', player), lambda state: True) + set_rule(world.get_region('Lake Hylia Central Island', player), lambda state: True) + set_rule(world.get_entrance('Zoras River', player), lambda state: True) + # lw boots-accessible locations + lw_boots_accessible_regions = [ + 'Bat Cave Drop Ledge', + 'Lake Hylia Island', + 'Desert Ledge', + 'Desert Ledge (Northeast)', + 'Desert Palace Lone Stairs', + 'Desert Palace Entrance (North) Spot', + 'Death Mountain', + 'Death Mountain Return Ledge', + 'East Death Mountain (Bottom)', + 'East Death Mountain (Top)', + 'Death Mountain (Top)', + 'Spectacle Rock', + 'Death Mountain Floating Island (Light World)', + ] + # dw boots-accessible regions + dw_boots_accessible_regions = [ + 'East Dark World', + 'Northeast Dark World', + 'West Dark World', + 'Hammer Peg Area', + 'Bumper Cave Ledge', + 'Dark Desert', + 'Dark Death Mountain (Top)', + 'Dark Death Mountain (East Bottom)', + 'Dark Death Mountain Ledge', + 'Death Mountain Floating Island (Dark World)', + 'Turtle Rock (Top)', + ] + # set up boots-accessible regions + if world.mode[player] != 'inverted': + lw_boots_accessible_regions.append('Cave 45 Ledge') + lw_boots_accessible_regions.append('Graveyard Ledge') + # couple other random spots + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player) and (state.has_Mirror(player) or state.has_Boots(player))) + set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: (state.has('Ocarina', player) or state.has_Boots(player)) and state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: (state.has('Hammer', player) or state.has_Boots(player)) and state.can_lift_rocks(player)) + set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has_Boots(player)) + add_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_Boots(player) and state.has_Pearl(player), 'or') + needs_boots = lambda state: state.has_Boots(player) + needs_boots_and_pearl = lambda state: state.has_Boots(player) and state.has_Pearl(player) + for spot in lw_boots_accessible_regions: + for location in world.get_region(spot, player).locations: + add_rule(world.get_location(location, player), needs_boots_and_pearl if world.mode[player] == 'inverted' else needs_boots, 'or') + for spot in dw_boots_accessible_regions: + for location in world.get_region(spot, player).locations: + add_rule(world.get_location(location, player), needs_boots if world.mode[player] == 'inverted' else needs_boots_and_pearl, 'or') + # bunny DMD rules + if world.mode[player] != 'inverted': + # set up some mirror-accessible dw entrances. + boots_and_mirror = lambda state: state.has_Boots(player) and state.has_Mirror(player) + add_rule(world.get_entrance('Dark Sanctuary Hint', player), boots_and_mirror, 'or') # should suffice to give us west dark world access + for spot in world.get_region('Dark Death Mountain (East Bottom)', player).locations: + add_rule(world.get_location(spot, player), boots_and_mirror, 'or') + # dw entrances accessible with mirror and hookshot + mirror_hookshot_accessible_dw_locations = [ + 'Pyramid Fairy', + 'Pyramid Entrance', + 'Pyramid Drop', + ] + mirror_hookshot_accessible_dw_locations.extend(world.get_region('Dark Death Mountain Ledge', player).locations) + for spot in mirror_hookshot_accessible_dw_locations: + add_rule(world.get_entrance(spot, player), lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.has('Hookshot', player), 'or') + # dw entrances accessible with mirror and titans + boots_mirror_titans = lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.can_lift_heavy_rocks(player) + add_rule(world.get_entrance('Mire Shed', player), boots_mirror_titans, 'or') + add_rule(world.get_location('Frog', player), boots_mirror_titans, 'or') + add_conditional_lamps(world, player) + + def open_rules(world, player): # softlock protection as you can reach the sewers small key door with a guard drop key set_rule(world.get_location('Hyrule Castle - Boomerang Chest', player), lambda state: state.has_key('Small Key (Escape)', player)) From acce83a8d8450662dc5cacd114b4a02d41fcabaa Mon Sep 17 00:00:00 2001 From: qadan Date: Fri, 3 Jan 2020 04:06:00 -0400 Subject: [PATCH 2/6] accidentally moved a thing --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 41015113..dbcdd43b 100644 --- a/Rules.py +++ b/Rules.py @@ -359,6 +359,7 @@ def default_rules(world, player): set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) # Caution: If king's grave is releaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Desert Palace Stairs', player), lambda state: state.has('Book of Mudora', player)) @@ -626,7 +627,6 @@ def no_glitches_rules(world, player): set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) else: - set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Zoras River', player), lambda state: state.has_Pearl(player) and (state.has('Flippers', player) or state.can_lift_rocks(player))) set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to set_rule(world.get_entrance('Lake Hylia Island', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) From 12c5e3a3907ad44f97ef35dd4c48a2b3598bebd9 Mon Sep 17 00:00:00 2001 From: qadan Date: Fri, 3 Jan 2020 18:43:50 -0400 Subject: [PATCH 3/6] first pass at superbunny rules --- Rules.py | 75 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/Rules.py b/Rules.py index dbcdd43b..5fb44d75 100644 --- a/Rules.py +++ b/Rules.py @@ -647,17 +647,33 @@ def no_glitches_rules(world, player): add_conditional_lamps(world, player) +DW_Entrances = ['Bumper Cave (Bottom)', + 'Superbunny Cave (Top)', + 'Superbunny Cave (Bottom)', + 'Hookshot Cave', + 'Bumper Cave (Top)', + 'Hookshot Cave Back Entrance', + 'Dark Death Mountain Ledge (East)', + 'Turtle Rock Isolated Ledge Entrance', + 'Thieves Town', + 'Skull Woods Final Section', + 'Ice Palace', + 'Misery Mire', + 'Palace of Darkness', + 'Swamp Palace', + 'Turtle Rock', + 'Dark Death Mountain Ledge (West)'] + +def check_is_dark_world(region): + for entrance in region.entrances: + if entrance.name in DW_Entrances: + return True + return False + + def add_conditional_lamps(world, player): # Light cones in standard depend on which world we actually are in, not which one the location would normally be # We add Lamp requirements only to those locations which lie in the dark world (or everything if open - DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Bumper Cave (Top)', 'Hookshot Cave Back Entrance', 'Dark Death Mountain Ledge (East)', - 'Turtle Rock Isolated Ledge Entrance', 'Thieves Town', 'Skull Woods Final Section', 'Ice Palace', 'Misery Mire', 'Palace of Darkness', 'Swamp Palace', 'Turtle Rock', 'Dark Death Mountain Ledge (West)'] - - def check_is_dark_world(region): - for entrance in region.entrances: - if entrance.name in DW_Entrances: - return True - return False def add_conditional_lamp(spot, region, spottype='Location'): if spottype == 'Location': @@ -738,7 +754,6 @@ def overworld_glitches_rules(world, player): # couple other random spots set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player) and (state.has_Mirror(player) or state.has_Boots(player))) set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: (state.has('Ocarina', player) or state.has_Boots(player)) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: (state.has('Hammer', player) or state.has_Boots(player)) and state.can_lift_rocks(player)) set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has_Boots(player)) add_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_Boots(player) and state.has_Pearl(player), 'or') needs_boots = lambda state: state.has_Boots(player) @@ -769,6 +784,32 @@ def overworld_glitches_rules(world, player): boots_mirror_titans = lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.can_lift_heavy_rocks(player) add_rule(world.get_entrance('Mire Shed', player), boots_mirror_titans, 'or') add_rule(world.get_location('Frog', player), boots_mirror_titans, 'or') + + # all entrances you can't mirror bunny into + invalid_mirror_bunny_entrances_lw = [ + 'Bonk Rock Cave', + 'Bonk Fairy (Light)', + 'Blinds Hideout', + '50 Rupee Cave', + '20 Rupee Cave', + 'Checkerboard Cave', + 'Light Hype Fairy', + 'Waterfall of Wishing', + 'Light World Bomb Hut', + 'Mini Moldorm Cave', + 'Ice Rod Cave', + 'Hyrule Castle Secret Entrance Stairs', + 'Sanctuary Grave', + 'Kings Grave', + 'Tower of Hera', + ] + # also, you can do mini moldorm cave and spiral cave - but you need a sword + superbunny_mirror_sword = lambda state: state.has_Mirror(player) and state.has_sword(player) + mini_moldorm_cave = world.get_region('Mini Moldorm Cave', player) + if check_is_dark_world(mini_moldorm_cave): + for spot in mini_moldorm_cave.locations: + add_rule(world.get_location(spot, player), superbunny_mirror_sword, 'or') + add_rule(world.get_location('Spiral Cave', player), superbunny_mirror_sword, 'or') add_conditional_lamps(world, player) @@ -1249,6 +1290,7 @@ def set_inverted_big_bomb_rules(world, player): 'Dark Desert Hint', 'Dark Desert Fairy', 'Misery Mire'] + LW_bush_entrances = ['Bush Covered House', 'Light World Bomb Hut', 'Graveyard Cave'] @@ -1318,7 +1360,9 @@ def set_bunny_rules(world, player): 'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)', 'Fairy Ascension Cave (Drop)'] bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins'] - + # interiors that are accessible if you're in bunny state but have the mirror; OWG-only. + superbunny_accessible_locations = ['Waterfall of Wishing - Left', 'Waterfall of Wishing - Right', 'King\'s Tomb', 'Floodgate', 'Floodgate Chest', 'Cave 45', 'Bonk Rock Cave', 'Brewery', 'C-Shaped House', 'Chest Game', 'Mire Shed - Left', 'Mire Shed - Right', 'Secret Passage', 'Ice Rod Cave', 'Pyramid Fairy - Left', 'Pyramid Fairy - Right'] + invalid_mirror_bunny_entrances_dw = ['Skull Woods Final Section (Entrance)', 'Hype Cave', 'Bonk Fairy (Dark)', 'Thieves Town', 'Dark World Hammer Peg Cave', 'Brewery', 'Hookshot Cave', 'Hookshot Cave Exit (South)', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Spike Cave'] def path_to_access_rule(path, entrance): return lambda state: state.can_reach(entrance) and all(rule(state) for rule in path) @@ -1326,8 +1370,10 @@ def set_bunny_rules(world, player): def options_to_access_rule(options): return lambda state: any(rule(state) for rule in options) - def get_rule_to_add(region): + def get_rule_to_add(region, location = None): if not region.is_light_world: + if location in superbunny_accessible_locations and region.name not in invalid_mirror_bunny_entrances_dw: + return lambda state: (state.can_reach(region) and state.has_Mirror(player)) or state.has_Pearl(player) return lambda state: state.has_Pearl(player) # in this case we are mixed region. # we collect possible options. @@ -1351,7 +1397,7 @@ def set_bunny_rules(world, player): new_path = path + [entrance.access_rule] seen.add(new_region) if not new_region.is_light_world: - continue # we don't care about pure dark world entrances + continue # we don't care about pure dark world entrances in non-owg if new_region.is_dark_world: queue.append((new_region, new_path)) else: @@ -1379,7 +1425,7 @@ def set_bunny_rules(world, player): if location.name in bunny_accessible_locations: continue - add_rule(location, get_rule_to_add(location.parent_region)) + add_rule(location, get_rule_to_add(location.parent_region, location.name)) def set_inverted_bunny_rules(world, player): @@ -1388,8 +1434,7 @@ def set_inverted_bunny_rules(world, player): bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)', 'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)', 'Fairy Ascension Cave (Drop)', 'The Sky'] - bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest'] - + bunny_acces1sible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest'] def path_to_access_rule(path, entrance): return lambda state: state.can_reach(entrance) and all(rule(state) for rule in path) From f151b05b49335dce2926b0be0d9ac8e89519f35e Mon Sep 17 00:00:00 2001 From: qadan Date: Mon, 6 Jan 2020 12:53:38 -0400 Subject: [PATCH 4/6] accidentally a thing --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 5fb44d75..735461c5 100644 --- a/Rules.py +++ b/Rules.py @@ -1434,7 +1434,7 @@ def set_inverted_bunny_rules(world, player): bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)', 'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)', 'Fairy Ascension Cave (Drop)', 'The Sky'] - bunny_acces1sible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest'] + bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest'] def path_to_access_rule(path, entrance): return lambda state: state.can_reach(entrance) and all(rule(state) for rule in path) From 62e84dfafd1a749d05762fafaaa4a03a08dc4d6a Mon Sep 17 00:00:00 2001 From: qadan Date: Mon, 6 Jan 2020 13:48:14 -0500 Subject: [PATCH 5/6] entrances and locations --- Rules.py | 130 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 37 deletions(-) diff --git a/Rules.py b/Rules.py index 735461c5..4f5f4a10 100644 --- a/Rules.py +++ b/Rules.py @@ -713,57 +713,113 @@ def add_conditional_lamps(world, player): def overworld_glitches_rules(world, player): - # spots that are immediately accessible + # spots that are immediately accessible due to fake flippering set_rule(world.get_entrance('Hobo Bridge', player), lambda state: True) set_rule(world.get_region('Lake Hylia Central Island', player), lambda state: True) set_rule(world.get_entrance('Zoras River', player), lambda state: True) - # lw boots-accessible locations - lw_boots_accessible_regions = [ + + # boots-accessible stuff + lw_boots_accessible_entrances = [ 'Bat Cave Drop Ledge', + 'Bat Cave Drop Ledge Mirror Spot', + 'Lake Hylia Island Mirror Spot', + 'Desert Ledge Return Rocks', + 'Desert Ledge Mirror Spot', + 'Checkerboard Cave', + 'Old Man House Exit (Bottom)', + 'Desert Ledge (Northeast) Mirror Spot', + 'Death Mountain Return Cave Exit (East)', + 'Desert Palace Entrance (North) Rocks', + 'Desert Palace Entrance (North) Mirror Spot', + 'Flute Spot 1', + 'Broken Bridge (East)', + 'Death Mountain Drop', + 'Death Mountain Return Cave Exit (West)', + 'Old Man Cave Exit (East)', + 'Bumper Cave Ledge Mirror Spot', + 'Broken Bridge (West)', + 'East Death Mountain Drop', + 'Spiral Cave Ledge Drop', + 'Fairy Ascension Drop', + 'East Death Mountain (Top)', + 'East Death Mountain (Top) Mirror Spot', + 'Death Mountain (Top)', + 'Spectacle Rock Drop', + 'Spectacle Rock Mirror Spot', + 'Floating Island Mirror Spot', + 'Fairy Ascension Cave Exit (Top)', + 'Fairy Ascension Cave Exit (Bottom)', + 'Death Mountain Return Cave Exit (East)', + 'Spiral Cave Exit', + ] + lw_boots_accessible_locations = [ 'Lake Hylia Island', 'Desert Ledge', - 'Desert Ledge (Northeast)', - 'Desert Palace Lone Stairs', - 'Desert Palace Entrance (North) Spot', - 'Death Mountain', - 'Death Mountain Return Ledge', - 'East Death Mountain (Bottom)', - 'East Death Mountain (Top)', - 'Death Mountain (Top)', + 'Ether Tablet', 'Spectacle Rock', - 'Death Mountain Floating Island (Light World)', + 'Floating Island', ] - # dw boots-accessible regions - dw_boots_accessible_regions = [ - 'East Dark World', - 'Northeast Dark World', - 'West Dark World', - 'Hammer Peg Area', + dw_boots_accessible_entrances = [ + 'Northeast Dark World Broken Bridge Pass', + 'Death Mountain Return Cave Exit (West)', + 'Peg Area Rocks', + 'Grassy Lawn Pegs', + 'West Dark World Gap', + 'Bumper Cave Ledge Drop', + 'Turtle Rock Ledge Exit (West)', + 'Turtle Rock Isolated Ledge Exit', + 'Dark Desert Teleporter', + 'Turtle Rock Exit (Front)', + 'Turtle Rock Drop', + 'Floating Island Drop', + 'Turtle Rock Ledge Exit (East)', + 'Dark Death Mountain Drop (East)', + 'Village of Outcasts Drop', + 'Dark Lake Hylia Ledge', + 'Hype Cave', + 'Dark World Potion Shop', + 'Big Bomb Shop', + 'Archery Game', + 'Brewery', + 'C-Shaped House', + 'Chest Game', + 'Thieves Town', + 'Graveyard Ledge Mirror Spot', + 'Kings Grave Mirror Spot', + 'Bumper Cave Entrance Rock', + 'Red Shield Shop', + 'Dark Sanctuary Hint', + 'Fortune Teller (Dark)', + 'Dark World Lumberjack Shop', + ] + dw_boots_accessible_locations = [ + 'Catfish', + 'Frog', + 'Dark Blacksmith Ruins', 'Bumper Cave Ledge', - 'Dark Desert', - 'Dark Death Mountain (Top)', - 'Dark Death Mountain (East Bottom)', - 'Dark Death Mountain Ledge', - 'Death Mountain Floating Island (Dark World)', - 'Turtle Rock (Top)', ] # set up boots-accessible regions if world.mode[player] != 'inverted': - lw_boots_accessible_regions.append('Cave 45 Ledge') - lw_boots_accessible_regions.append('Graveyard Ledge') + lw_boots_accessible_entrances.append('Cave 45 Mirror Spot') + lw_boots_accessible_entrances.append('Graveyard Ledge Mirror Spot') # couple other random spots set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player) and (state.has_Mirror(player) or state.has_Boots(player))) - set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: (state.has('Ocarina', player) or state.has_Boots(player)) and state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.has('Ocarina', player) or (state.has_Boots(player) and state.can_lift_heavy_rocks(player))) set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has_Boots(player)) add_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_Boots(player) and state.has_Pearl(player), 'or') + add_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Boots(player), 'or') + add_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.has_Boots(player) and state.has('Hammer', player)) needs_boots = lambda state: state.has_Boots(player) needs_boots_and_pearl = lambda state: state.has_Boots(player) and state.has_Pearl(player) - for spot in lw_boots_accessible_regions: - for location in world.get_region(spot, player).locations: - add_rule(world.get_location(location, player), needs_boots_and_pearl if world.mode[player] == 'inverted' else needs_boots, 'or') - for spot in dw_boots_accessible_regions: - for location in world.get_region(spot, player).locations: - add_rule(world.get_location(location, player), needs_boots if world.mode[player] == 'inverted' else needs_boots_and_pearl, 'or') + for entrance in lw_boots_accessible_entrances: + add_rule(world.get_entrance(entrance, player), needs_boots_and_pearl if world.mode[player] == 'inverted' else needs_boots, 'or') + for location in lw_boots_accessible_locations: + add_rule(world.get_location(location, player), needs_boots_and_pearl if world.mode[player] == 'inverted' else needs_boots, 'or') + # no inverted rules here; no DMD bunny known so far + for entrance in dw_boots_accessible_entrances: + add_rule(world.get_entrance(entrance, player), needs_boots_and_pearl, 'or') + for location in dw_boots_accessible_locations: + add_rule(world.get_location(location, player), needs_boots_and_pearl, 'or') # bunny DMD rules if world.mode[player] != 'inverted': # set up some mirror-accessible dw entrances. @@ -779,13 +835,13 @@ def overworld_glitches_rules(world, player): ] mirror_hookshot_accessible_dw_locations.extend(world.get_region('Dark Death Mountain Ledge', player).locations) for spot in mirror_hookshot_accessible_dw_locations: - add_rule(world.get_entrance(spot, player), lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.has('Hookshot', player), 'or') + add_rule(world.get_entrance(spot, player), lambda state: state.has_Mirror(player) and state.has('Hookshot', player), 'or') # dw entrances accessible with mirror and titans - boots_mirror_titans = lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.can_lift_heavy_rocks(player) + boots_mirror_titans = lambda state: state.has_Mirror(player) and state.can_lift_heavy_rocks(player) add_rule(world.get_entrance('Mire Shed', player), boots_mirror_titans, 'or') add_rule(world.get_location('Frog', player), boots_mirror_titans, 'or') - # all entrances you can't mirror bunny into + # all entrances you can't mirror bunny into. @todo: use for inverted invalid_mirror_bunny_entrances_lw = [ 'Bonk Rock Cave', 'Bonk Fairy (Light)', @@ -1372,7 +1428,7 @@ def set_bunny_rules(world, player): def get_rule_to_add(region, location = None): if not region.is_light_world: - if location in superbunny_accessible_locations and region.name not in invalid_mirror_bunny_entrances_dw: + if world.logic[player] == 'owglitches' and location in superbunny_accessible_locations and region.name not in invalid_mirror_bunny_entrances_dw: return lambda state: (state.can_reach(region) and state.has_Mirror(player)) or state.has_Pearl(player) return lambda state: state.has_Pearl(player) # in this case we are mixed region. From c677a875f2a124bd0930467b2952e0587d24839b Mon Sep 17 00:00:00 2001 From: qadan Date: Thu, 9 Jan 2020 14:43:21 -0500 Subject: [PATCH 6/6] accidentally another thing --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 4f5f4a10..5c2a7e72 100644 --- a/Rules.py +++ b/Rules.py @@ -860,7 +860,7 @@ def overworld_glitches_rules(world, player): 'Tower of Hera', ] # also, you can do mini moldorm cave and spiral cave - but you need a sword - superbunny_mirror_sword = lambda state: state.has_Mirror(player) and state.has_sword(player) + superbunny_mirror_sword = lambda state: state.has_Boots(player) and state.has_Mirror(player) and state.has_sword(player) mini_moldorm_cave = world.get_region('Mini Moldorm Cave', player) if check_is_dark_world(mini_moldorm_cave): for spot in mini_moldorm_cave.locations: