From 4986821e92145569a08fd03420c03a2a5a9ea5f4 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 11:09:12 -0600 Subject: [PATCH 01/17] Created pseudoitem for TR entry --- ItemList.py | 3 +++ Items.py | 1 + Regions.py | 3 ++- Rules.py | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ItemList.py b/ItemList.py index b36e071b..26b20c03 100644 --- a/ItemList.py +++ b/ItemList.py @@ -252,6 +252,9 @@ def generate_itempool(world, player): world.push_item(world.get_location('Swamp Drain', player), ItemFactory('Drained Swamp', player), False) world.get_location('Swamp Drain', player).event = True world.get_location('Swamp Drain', player).locked = True + world.push_item(world.get_location('Turtle Medallion Pad', player), ItemFactory('Turtle Opened', player), False) + world.get_location('Turtle Medallion Pad', player).event = True + world.get_location('Turtle Medallion Pad', player).locked = True world.push_item(world.get_location('Attic Cracked Floor', player), ItemFactory('Shining Light', player), False) world.get_location('Attic Cracked Floor', player).event = True world.get_location('Attic Cracked Floor', player).locked = True diff --git a/Items.py b/Items.py index e64b0bda..8b04e01c 100644 --- a/Items.py +++ b/Items.py @@ -191,6 +191,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Trench 1 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Trench 2 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Drained Swamp': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Turtle Opened': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Shining Light': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Maiden Rescued': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Maiden Unmasked': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), diff --git a/Regions.py b/Regions.py index 8f637e3a..8eba88ee 100644 --- a/Regions.py +++ b/Regions.py @@ -145,7 +145,7 @@ def create_regions(world, player): create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot'], 'a dark floating island'), create_dw_region(player, 'Turtle Rock Area', None, ['Turtle Rock Tail Ledge Drop', 'Turtle Rock', 'TR Pegs Area Mirror Spot', 'Turtle Rock WN']), - create_dw_region(player, 'Turtle Rock Ledge', None, ['Turtle Rock Ledge Drop', 'Turtle Rock Teleporter']), + create_dw_region(player, 'Turtle Rock Ledge', ['Turtle Medallion Pad'], ['Turtle Rock Ledge Drop', 'Turtle Rock Teleporter']), create_dw_region(player, 'Bumper Cave Area', None, ['Bumper Cave Entrance Rock', 'Mountain Entry Mirror Spot', 'Bumper Cave NW', 'Bumper Cave SE']), create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave Ledge Drop', 'Bumper Cave (Bottom)', 'Mountain Entry Entrance Mirror Spot']), create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Entrance Drop', 'Bumper Cave (Top)', 'Mountain Entry Ledge Mirror Spot'], 'a ledge with an item'), @@ -1598,6 +1598,7 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), 'Trench 1 Switch': (None, None, False, None), 'Trench 2 Switch': (None, None, False, None), 'Swamp Drain': (None, None, False, None), + 'Turtle Medallion Pad': (None, None, False, None), 'Attic Cracked Floor': (None, None, False, None), 'Suspicious Maiden': (None, None, False, None), 'Revealing Light': (None, None, False, None), diff --git a/Rules.py b/Rules.py index 5dc042a3..f31c874d 100644 --- a/Rules.py +++ b/Rules.py @@ -854,7 +854,7 @@ def default_rules(world, player): set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock Ledge', 'Region', player)) # sword required to cast magic (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.has('Turtle Opened', player)) # sword required to cast magic (!) set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) @@ -1327,6 +1327,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) add_bunny_rule(world.get_location('Maze Race', player), player) add_bunny_rule(world.get_location('Flute Spot', player), player) + add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) add_bunny_rule(world.get_location('Catfish', player), player) add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) @@ -1345,7 +1346,6 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) - add_bunny_rule(world.get_entrance('Turtle Rock', player), player) add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull add_bunny_rule(world.get_entrance('Brewery', player), player) # bomb required add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl @@ -1656,7 +1656,7 @@ def swordless_rules(world, player): set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has_beaten_aga(player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock Ledge', 'Region', player)) # sword not required to use medallion for opening in swordless (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.has('Turtle Opened', player)) # sword not required to use medallion for opening in swordless (!) add_bunny_rule(world.get_entrance('Misery Mire', player), player) add_bunny_rule(world.get_entrance('Turtle Rock', player), player) From 09f81d8b6995a218faf53ab8219e09b52f05d0aa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 11:10:10 -0600 Subject: [PATCH 02/17] Removal of indirect connections --- BaseClasses.py | 9 --------- EntranceShuffle.py | 24 ------------------------ 2 files changed, 33 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 3a8d6604..c645ce8d 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -641,15 +641,6 @@ class CollectionState(object): queue.append((conn, new_crystal_state)) self.path[new_region] = (new_region.name, self.path.get(connection, None)) - - # Retry connections if the new region can unblock them - from EntranceShuffle import indirect_connections - if new_region.name in indirect_connections: - new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player) - if new_entrance in bc and new_entrance.parent_region in rrp: - new_crystal_state = rrp[new_entrance.parent_region] - if (new_entrance, new_crystal_state) not in queue: - queue.append((new_entrance, new_crystal_state)) # else those connections that are not accessible yet if self.is_small_door(connection): door = connection.door if connection.door.smallKey else connection.door.controller diff --git a/EntranceShuffle.py b/EntranceShuffle.py index c7586275..1bd1e72b 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2296,30 +2296,6 @@ one_way_ledges = { 'Ice Lake Ledge (West)', 'Ice Lake Ledge (East)'} } - -indirect_connections = { - 'Turtle Rock Ledge': 'Turtle Rock', - 'Big Bomb Shop': 'Pyramid Crack', - #'East Dark World': 'Pyramid Fairy', - 'Pyramid Area': 'Pyramid Crack', # HC Ledge/Courtyard - #'Dark Desert': 'Pyramid Fairy', - #'Misery Mire Area': 'Pyramid Fairy', # Desert/Checkerboard Ledge - #'West Dark World': 'Pyramid Fairy', - #'Dark Chapel Area': 'Pyramid Fairy', # Bonk Rocks - #'Dark Graveyard North': 'Pyramid Fairy', # Graveyard Ledge/Kings Tomb - #'South Dark World': 'Pyramid Fairy', - #'Dig Game Ledge': 'Pyramid Fairy', # Brother House Left - #'Stumpy Approach Area': 'Pyramid Fairy', # Cave 45 - # Inverted Cases - #'Light World': 'Pyramid Fairy', - #'Lost Woods West Area': 'Pyramid Fairy', # Skull Woods Back - #'East Death Mountain (Top East)': 'Pyramid Fairy', # Floating Island - #'Blacksmith Area': 'Pyramid Fairy', # Hammerpegs - #'Forgotten Forest Area': 'Pyramid Fairy', # Shield Shop - #'Desert Area': 'Pyramid Fairy', # Mire Area - 'Old Man Drop Off': 'Old Man S&Q', - 'Old Man Cave': 'Old Man S&Q' -} # format: # Key=Name # addr = (door_index, exitdata, ow_flag) # multiexit From a136f1dd8ed7f4238c5abc10016c9fea2611af62 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 11:15:29 -0600 Subject: [PATCH 03/17] Created pseudoitem for TR entry --- Regions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Regions.py b/Regions.py index 8eba88ee..bf55213c 100644 --- a/Regions.py +++ b/Regions.py @@ -1198,8 +1198,8 @@ def adjust_locations(world, player): # player address? it is in the shop table index += 1 # unreal events: - for l in ['Ganon', 'Agahnim 1', 'Agahnim 2', 'Dark Blacksmith Ruins', 'Middle Aged Man', - 'Frog', 'Missing Smith', 'Floodgate', 'Trench 1 Switch', 'Trench 2 Switch', 'Swamp Drain', + for l in ['Ganon', 'Agahnim 1', 'Agahnim 2', 'Frog', 'Missing Smith', 'Dark Blacksmith Ruins', 'Middle Aged Man', + 'Floodgate', 'Trench 1 Switch', 'Trench 2 Switch', 'Swamp Drain', 'Turtle Medallion Pad', 'Attic Cracked Floor', 'Suspicious Maiden', 'Revealing Light', 'Big Bomb', 'Pyramid Crack', 'Ice Block Drop', 'Lost Old Man', 'Old Man Drop Off', 'Zelda Pickup', 'Zelda Drop Off', 'Skull Star Tile']: location = world.get_location_unsafe(l, player) From 5effa39b401dff2e567250f843c819f7a301dbb1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 11:18:31 -0600 Subject: [PATCH 04/17] Giving chickens a base price for shops --- Items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Items.py b/Items.py index 8b04e01c..6f37f059 100644 --- a/Items.py +++ b/Items.py @@ -84,7 +84,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Arrows (5)': (False, False, None, 0xB5, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'), 'Small Magic': (False, False, None, 0x45, 5, 'A bit of magic', 'and the bit of magic', 'bit-o-magic kid', 'magic bit for sale', 'fungus for magic', 'magic boy conjures again', 'a bit of magic'), 'Big Magic': (False, False, None, 0xB4, 40, 'A lot of magic', 'and lots of magic', 'lot-o-magic kid', 'magic refill for sale', 'fungus for magic', 'magic boy conjures again', 'a magic refill'), - 'Chicken': (False, False, None, 0xB3, 999, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'), + 'Chicken': (False, False, None, 0xB3, 5, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'), 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'Increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), From 21b7d6fd8a175ec8756a4c4504ed4392c02e5540 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 12:56:00 -0600 Subject: [PATCH 05/17] Created pseudoitem for TR entry --- Rules.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Rules.py b/Rules.py index f31c874d..04d5802f 100644 --- a/Rules.py +++ b/Rules.py @@ -830,6 +830,7 @@ def default_rules(world, player): set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player)) # sword required to cast magic (!) # Bonk Item Access if world.shuffle_bonk_drops[player]: @@ -854,7 +855,7 @@ def default_rules(world, player): set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.has('Turtle Opened', player)) # sword required to cast magic (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has('Turtle Opened', player)) set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) @@ -1656,9 +1657,9 @@ def swordless_rules(world, player): set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has_beaten_aga(player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.has('Turtle Opened', player)) # sword not required to use medallion for opening in swordless (!) + set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_turtle_rock_medallion(player)) # sword not required to use medallion for opening in swordless (!) add_bunny_rule(world.get_entrance('Misery Mire', player), player) - add_bunny_rule(world.get_entrance('Turtle Rock', player), player) + add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) std_kill_rooms = { 'Hyrule Dungeon Armory Main': ['Hyrule Dungeon Armory S', 'Hyrule Dungeon Armory ES'], # One green guard From 2c96f31bc8e23fc944637792370b1e9aa935ebae Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 21 Nov 2022 15:22:05 -0600 Subject: [PATCH 06/17] Removal of unused deprecated light cone logic --- Rules.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Rules.py b/Rules.py index 04d5802f..4d19e258 100644 --- a/Rules.py +++ b/Rules.py @@ -1554,25 +1554,13 @@ def forbid_bomb_jump_requirements(world, player): add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) -# 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_lamps(world, player): - def add_conditional_lamp(spot, region, spottype='Location'): + def add_conditional_lamp(spot, spottype='Location'): if spottype == 'Location': spot = world.get_location(spot, player) else: spot = world.get_entrance(spot, player) - if (not world.dark_world_light_cone and check_is_dark_world(world.get_region(region, player))) or (not world.light_world_light_cone and not check_is_dark_world(world.get_region(region, player))): - add_lamp_requirement(spot, player) + add_lamp_requirement(spot, player) dark_rooms = { 'TR Dark Ride': {'sewer': False, 'entrances': ['TR Dark Ride Up Stairs', 'TR Dark Ride SW', 'TR Dark Ride Path'], 'locations': []}, @@ -1628,10 +1616,10 @@ def add_conditional_lamps(world, player): if is_dark: dark_debug_set.add(region) for ent in info['entrances']: - add_conditional_lamp(ent, region, 'Entrance') + add_conditional_lamp(ent, 'Entrance') r = world.get_region(region, player) for loc in r.locations: - add_conditional_lamp(loc, region, 'Location') + add_conditional_lamp(loc, 'Location') logging.getLogger('').debug('Non Dark Regions: ' + ', '.join(set(dark_rooms.keys()).difference(dark_debug_set))) add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance') From 771795f521c4a40341ebce6ea5d98c7a3cb3234a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 23 Nov 2022 16:29:05 -0600 Subject: [PATCH 07/17] Removal of unused deprecated light cone logic --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 4d19e258..b8f0c871 100644 --- a/Rules.py +++ b/Rules.py @@ -1622,7 +1622,7 @@ def add_conditional_lamps(world, player): add_conditional_lamp(loc, 'Location') logging.getLogger('').debug('Non Dark Regions: ' + ', '.join(set(dark_rooms.keys()).difference(dark_debug_set))) - add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance') + add_conditional_lamp('Old Man House Front to Back', 'Entrance') def open_rules(world, player): # softlock protection as you can reach the sewers small key door with a guard drop key From 217fcc14da5cd33755c091612556bcd3ad88df80 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 27 Nov 2022 14:11:29 -0600 Subject: [PATCH 08/17] Modeled South Portal Area correctly for OWG prep --- OWEdges.py | 10 ++++++++-- OverworldShuffle.py | 8 ++++++++ Regions.py | 10 ++++++---- Rules.py | 12 ++++++++++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/OWEdges.py b/OWEdges.py index 3f615aaa..cb61a153 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1483,6 +1483,7 @@ OWExitTypes = { 'Tree Line WC Cliff Water Drop', 'C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Cliff Ledge Drop', + 'C Whirlpool Portal Cliff Ledge Drop', 'Statues Cliff Ledge Drop', 'Desert Ledge Drop', 'Checkerboard Ledge Drop', @@ -1538,6 +1539,7 @@ OWExitTypes = { 'Dark Tree Line WC Cliff Water Drop', 'Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Cliff Ledge Drop', + 'Dark C Whirlpool Portal Cliff Ledge Drop', 'Hype Cliff Ledge Drop', 'Misery Mire Teleporter Ledge Drop', 'Mire Cliff Ledge Drop', @@ -1622,9 +1624,11 @@ OWExitTypes = { 'Flute Boy Bush (North)', 'Cave 45 Inverted Leave', 'C Whirlpool Rock (Bottom)', + 'C Whirlpool Rock (Top)', + 'C Whirlpool Pegs (Right)', + 'C Whirlpool Pegs (Left)', 'C Whirlpool Water Entry', 'C Whirlpool Landing', - 'C Whirlpool Rock (Top)', 'Statues Water Entry', 'Statues Landing', 'Lake Hylia Central Water Drop', @@ -1684,9 +1688,11 @@ OWExitTypes = { 'Stumpy Approach Bush (South)', 'Stumpy Approach Bush (North)', 'Dark C Whirlpool Rock (Bottom)', + 'Dark C Whirlpool Rock (Top)', + 'Dark C Whirlpool Pegs (Right)', + 'Dark C Whirlpool Pegs (Left)', 'Dark C Whirlpool Water Entry', 'Dark C Whirlpool Landing', - 'Dark C Whirlpool Rock (Top)', 'Hype Cave Water Entry', 'Hype Cave Landing', 'Ice Lake Northeast Water Drop', diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 127a1280..d07b64f6 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1236,6 +1236,8 @@ mandatory_connections = [# Intra-tile OW Connections ('C Whirlpool Landing', 'C Whirlpool Area'), ('C Whirlpool Rock (Bottom)', 'C Whirlpool Outer Area'), #glove ('C Whirlpool Rock (Top)', 'C Whirlpool Area'), #glove + ('C Whirlpool Pegs (Right)', 'C Whirlpool Portal Area'), #hammer + ('C Whirlpool Pegs (Left)', 'C Whirlpool Area'), #hammer ('Statues Water Entry', 'Statues Water'), #flippers ('Statues Landing', 'Statues Area'), ('Lake Hylia Water Drop', 'Lake Hylia Water'), #flippers @@ -1321,6 +1323,8 @@ mandatory_connections = [# Intra-tile OW Connections ('Dark C Whirlpool Landing', 'Dark C Whirlpool Area'), ('Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Outer Area'), #glove ('Dark C Whirlpool Rock (Top)', 'Dark C Whirlpool Area'), #glove + ('Dark C Whirlpool Pegs (Right)', 'Dark C Whirlpool Portal Area'), #hammer + ('Dark C Whirlpool Pegs (Left)', 'Dark C Whirlpool Area'), #hammer ('Hype Cave Water Entry', 'Hype Cave Water'), #flippers ('Hype Cave Landing', 'Hype Cave Area'), ('Ice Lake Water Drop', 'Ice Lake Water'), #flippers @@ -1691,6 +1695,8 @@ ow_connections = { ('Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Area'), # OWG ('C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Outer Area'), # OWG ('Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Outer Area'), # OWG + ('C Whirlpool Portal Cliff Ledge Drop', 'C Whirlpool Portal Area'), #OWG + ('Dark C Whirlpool Portal Cliff Ledge Drop', 'Dark C Whirlpool Portal Area'), #OWG ('Desert C Whirlpool Cliff Ledge Drop', 'C Whirlpool Outer Area'), # OWG ('Mire C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Outer Area') # OWG ], [ @@ -1701,6 +1707,8 @@ ow_connections = { ('Dark C Whirlpool Cliff Ledge Drop', 'C Whirlpool Area'), # OWG ('C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Outer Area'), # OWG ('Dark C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Outer Area'), # OWG + ('C Whirlpool Portal Cliff Ledge Drop', 'Dark C Whirlpool Portal Area'), #OWG + ('Dark C Whirlpool Portal Cliff Ledge Drop', 'C Whirlpool Portal Area'), #OWG ('Desert C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Outer Area'), # OWG ('Mire C Whirlpool Cliff Ledge Drop', 'C Whirlpool Outer Area') # OWG ]), diff --git a/Regions.py b/Regions.py index bf55213c..9208094a 100644 --- a/Regions.py +++ b/Regions.py @@ -89,7 +89,7 @@ def create_regions(world, player): create_lw_region(player, 'Stone Bridge South Area', None, ['Stone Bridge Northbound', 'Hammer Bridge South Mirror Spot', 'Stone Bridge WS', 'Stone Bridge SC']), create_lw_region(player, 'Stone Bridge Water', None, ['Dark Hobo Mirror Spot', 'Stone Bridge WC', 'Stone Bridge EC'], 'Light World', Terrain.Water), create_lw_region(player, 'Hobo Bridge', ['Hobo'], ['Hobo EC'], 'Light World', Terrain.Water), - create_lw_region(player, 'Central Cliffs', None, ['Central Bonk Rocks Cliff Ledge Drop', 'Links House Cliff Ledge Drop', 'Stone Bridge Cliff Ledge Drop', 'Lake Hylia Area Cliff Ledge Drop', 'Lake Hylia Island FAWT Ledge Drop', 'Stone Bridge EC Cliff Water Drop', 'Tree Line WC Cliff Water Drop', 'C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Cliff Ledge Drop', 'Statues Cliff Ledge Drop']), + create_lw_region(player, 'Central Cliffs', None, ['Central Bonk Rocks Cliff Ledge Drop', 'Links House Cliff Ledge Drop', 'Stone Bridge Cliff Ledge Drop', 'Lake Hylia Area Cliff Ledge Drop', 'Lake Hylia Island FAWT Ledge Drop', 'Stone Bridge EC Cliff Water Drop', 'Tree Line WC Cliff Water Drop', 'C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Cliff Ledge Drop', 'C Whirlpool Portal Cliff Ledge Drop', 'Statues Cliff Ledge Drop']), create_lw_region(player, 'Tree Line Area', None, ['Lake Hylia Fairy', 'Dark Tree Line Mirror Spot', 'Tree Line WN', 'Tree Line NW', 'Tree Line SE']), create_lw_region(player, 'Tree Line Water', None, ['Tree Line WC', 'Tree Line SC'], 'Light World', Terrain.Water), create_lw_region(player, 'Eastern Nook Area', None, ['Long Fairy Cave', 'Darkness Nook Mirror Spot', 'East Hyrule Teleporter', 'Eastern Nook NE']), @@ -105,7 +105,8 @@ def create_regions(world, player): create_lw_region(player, 'Flute Boy Approach Area', None, ['Flute Boy Bush (South)', 'Cave 45 Inverted Approach', 'Stumpy Approach Mirror Spot', 'Flute Boy Approach NW', 'Flute Boy Approach EC']), create_lw_region(player, 'Flute Boy Bush Entry', None, ['Flute Boy Bush (North)', 'Stumpy Bush Entry Mirror Spot', 'Flute Boy Approach NC']), create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45 Inverted Leave', 'Cave 45 Ledge Drop', 'Cave 45']), - create_lw_region(player, 'C Whirlpool Area', None, ['C Whirlpool Rock (Bottom)', 'C Whirlpool Water Entry', 'Dark C Whirlpool Mirror Spot', 'South Hyrule Teleporter', 'C Whirlpool EN', 'C Whirlpool ES', 'C Whirlpool SC']), + create_lw_region(player, 'C Whirlpool Area', None, ['C Whirlpool Rock (Bottom)', 'C Whirlpool Pegs (Right)', 'C Whirlpool Water Entry', 'Dark C Whirlpool Mirror Spot', 'C Whirlpool EN', 'C Whirlpool ES', 'C Whirlpool SC']), + create_lw_region(player, 'C Whirlpool Portal Area', None, ['C Whirlpool Pegs (Left)', 'South Hyrule Teleporter']), create_lw_region(player, 'C Whirlpool Water', None, ['C Whirlpool Landing', 'C Whirlpool', 'C Whirlpool EC'], 'Light World', Terrain.Water), create_lw_region(player, 'C Whirlpool Outer Area', None, ['C Whirlpool Rock (Top)', 'Dark C Whirlpool Outer Mirror Spot', 'C Whirlpool WC', 'C Whirlpool NW']), create_lw_region(player, 'Statues Area', None, ['Statues Water Entry', 'Light Hype Fairy', 'Hype Cave Mirror Spot', 'Statues NC', 'Statues WN', 'Statues WS', 'Statues SC']), @@ -199,7 +200,7 @@ def create_regions(world, player): create_dw_region(player, 'Hammer Bridge South Area', None, ['Hammer Bridge Pegs (South)', 'Stone Bridge South Mirror Spot', 'Hammer Bridge WS', 'Hammer Bridge SC']), create_dw_region(player, 'Hammer Bridge Water', None, ['Hammer Bridge Pier', 'Hobo Mirror Spot', 'Hammer Bridge EC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Dark Central Cliffs', None, ['Dark Bonk Rocks Cliff Ledge Drop', 'Bomb Shop Cliff Ledge Drop', 'Hammer Bridge South Cliff Ledge Drop', 'Ice Lake Area Cliff Ledge Drop', 'Ice Palace Island FAWT Ledge Drop', - 'Hammer Bridge EC Cliff Water Drop', 'Dark Tree Line WC Cliff Water Drop', 'Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Cliff Ledge Drop', 'Hype Cliff Ledge Drop']), + 'Hammer Bridge EC Cliff Water Drop', 'Dark Tree Line WC Cliff Water Drop', 'Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Portal Cliff Ledge Drop', 'Hype Cliff Ledge Drop']), create_dw_region(player, 'Dark Tree Line Area', None, ['Dark Lake Hylia Fairy', 'Tree Line Mirror Spot', 'Dark Tree Line WN', 'Dark Tree Line NW', 'Dark Tree Line SE']), create_dw_region(player, 'Dark Tree Line Water', None, ['Dark Tree Line WC', 'Dark Tree Line SC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Palace of Darkness Nook Area', None, ['East Dark World Hint', 'East Dark World Teleporter', 'Eastern Nook Mirror Spot', 'Palace of Darkness Nook NE']), @@ -208,7 +209,8 @@ def create_regions(world, player): create_dw_region(player, 'Mire Northeast Cliffs', None, ['Mire Cliff Ledge Drop', 'Dark Checkerboard Cliff Ledge Drop', 'Archery Game Cliff Ledge Drop', 'Stumpy Approach Cliff Ledge Drop', 'Mire C Whirlpool Cliff Ledge Drop', 'Swamp Nook Cliff Ledge Drop', 'Swamp Cliff Ledge Drop', 'Bombos Tablet Ledge Mirror Spot']), create_dw_region(player, 'Stumpy Approach Area', None, ['Stumpy Approach Bush (South)', 'Cave 45 Mirror Spot', 'Stumpy Approach NW', 'Stumpy Approach EC']), create_dw_region(player, 'Stumpy Approach Bush Entry', None, ['Stumpy Approach Bush (North)', 'Flute Boy Entry Mirror Spot', 'Stumpy Approach NC']), - create_dw_region(player, 'Dark C Whirlpool Area', None, ['Dark C Whirlpool Rock (Bottom)', 'South Dark World Teleporter', 'C Whirlpool Mirror Spot', 'Dark C Whirlpool Water Entry', 'Dark C Whirlpool EN', 'Dark C Whirlpool ES', 'Dark C Whirlpool SC']), + create_dw_region(player, 'Dark C Whirlpool Area', None, ['Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Pegs (Right)', 'C Whirlpool Mirror Spot', 'Dark C Whirlpool Water Entry', 'Dark C Whirlpool EN', 'Dark C Whirlpool ES', 'Dark C Whirlpool SC']), + create_dw_region(player, 'Dark C Whirlpool Portal Area', None, ['Dark C Whirlpool Pegs (Left)', 'South Dark World Teleporter']), create_dw_region(player, 'Dark C Whirlpool Water', None, ['Dark C Whirlpool Landing', 'Dark C Whirlpool EC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Dark C Whirlpool Outer Area', None, ['Dark C Whirlpool Rock (Top)', 'C Whirlpool Outer Mirror Spot', 'Dark C Whirlpool WC', 'Dark C Whirlpool NW']), create_dw_region(player, 'Hype Cave Area', None, ['Hype Cave Water Entry', 'Hype Cave', 'Statues Mirror Spot', 'Hype Cave NC', 'Hype Cave WN', 'Hype Cave WS', 'Hype Cave SC']), diff --git a/Rules.py b/Rules.py index b8f0c871..8394fbd5 100644 --- a/Rules.py +++ b/Rules.py @@ -891,6 +891,8 @@ def default_rules(world, player): set_rule(world.get_entrance('Desert Ledge Inner Rocks', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Desert Pass Rocks (North)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player)) @@ -918,6 +920,8 @@ def default_rules(world, player): set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Zora Waterfall Water Entry', player), lambda state: state.has('Flippers', player)) @@ -1262,11 +1266,11 @@ def ow_inverted_rules(world, player): if not world.is_tile_swapped(0x33, player): set_rule(world.get_entrance('C Whirlpool Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('C Whirlpool Outer Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.can_lift_rocks(player)) else: set_rule(world.get_entrance('Dark C Whirlpool Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark C Whirlpool Outer Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) + set_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.can_lift_rocks(player)) if not world.is_tile_swapped(0x34, player): set_rule(world.get_entrance('Statues Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -1398,6 +1402,8 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Flute Boy Bush (South)', player), player) add_bunny_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), player) add_bunny_rule(world.get_entrance('C Whirlpool Rock (Top)', player), player) + add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), player) + add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (North)', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (South)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), player) @@ -1436,6 +1442,8 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Stumpy Approach Bush (South)', player), player) add_bunny_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), player) add_bunny_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), player) + add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), player) + add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), player) add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) add_bunny_rule(world.get_entrance('Zora Waterfall Water Entry', player), player) From 3ffe137f5762931bd7990472a76d051d40d5550e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 14:24:32 -0600 Subject: [PATCH 09/17] Modeled South Portal Area correctly for OWG prep --- OWEdges.py | 2 ++ OverworldShuffle.py | 4 ++-- Rules.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/OWEdges.py b/OWEdges.py index cb61a153..7fe4b016 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1137,6 +1137,7 @@ OWTileRegions = bidict({ 'Cave 45 Ledge': 0x32, 'C Whirlpool Area': 0x33, + 'C Whirlpool Portal Area': 0x33, 'C Whirlpool Water': 0x33, 'C Whirlpool Outer Area': 0x33, @@ -1274,6 +1275,7 @@ OWTileRegions = bidict({ 'Stumpy Approach Bush Entry': 0x72, 'Dark C Whirlpool Area': 0x73, + 'Dark C Whirlpool Portal Area': 0x73, 'Dark C Whirlpool Water': 0x73, 'Dark C Whirlpool Outer Area': 0x73, diff --git a/OverworldShuffle.py b/OverworldShuffle.py index d07b64f6..c6be3b90 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1690,7 +1690,7 @@ ow_connections = { 0x33: ([ ('C Whirlpool Mirror Spot', 'C Whirlpool Area'), ('C Whirlpool Outer Mirror Spot', 'C Whirlpool Outer Area'), - ('South Hyrule Teleporter', 'Dark C Whirlpool Area'), + ('South Hyrule Teleporter', 'Dark C Whirlpool Portal Area'), ('C Whirlpool Cliff Ledge Drop', 'C Whirlpool Area'), # OWG ('Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Area'), # OWG ('C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Outer Area'), # OWG @@ -1702,7 +1702,7 @@ ow_connections = { ], [ ('Dark C Whirlpool Mirror Spot', 'Dark C Whirlpool Area'), ('Dark C Whirlpool Outer Mirror Spot', 'Dark C Whirlpool Outer Area'), - ('South Dark World Teleporter', 'C Whirlpool Area'), + ('South Dark World Teleporter', 'C Whirlpool Portal Area'), ('C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Area'), # OWG ('Dark C Whirlpool Cliff Ledge Drop', 'C Whirlpool Area'), # OWG ('C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Outer Area'), # OWG diff --git a/Rules.py b/Rules.py index 8394fbd5..ec4aec40 100644 --- a/Rules.py +++ b/Rules.py @@ -199,7 +199,7 @@ def global_rules(world, player): set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Deliver Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Big Bomb', player), lambda state: state.has('Crystal 5', player) and state.has('Crystal 6', player)) set_rule(world.get_location('Pyramid Crack', player), lambda state: state.has('Pick Up Big Bomb', player)) - set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has('Detonate Big Bomb', player)) + set_rule(world.get_entrance('Pyramid Crack', player), lambda state: state.has('Detonate Big Bomb', player)) set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player)) From 16862b4afdedfed58f144f1553c09563b13c9277 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 14:35:17 -0600 Subject: [PATCH 10/17] Fixed OWG logic to apply logic in correct world --- OverworldGlitchRules.py | 141 +++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 66 deletions(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index f0aecbef..0c705028 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -142,21 +142,15 @@ def get_boots_clip_exits_lw(world, player): """ for name, parent_region, target_region in boots_clips_local: - if not world.is_tile_swapped(OWTileRegions[parent_region], player): + if world.is_tile_lw_like(OWTileRegions[parent_region], player): yield(name, parent_region, target_region) - for name, parent_region, target_region in boots_clips: - parent_swapped, target_swapped = get_swapped_status(world, player, parent_region, target_region) - if parent_region[0] and not parent_swapped: - if target_region[0] and not target_swapped: - yield(name[0], parent_region[0], target_region[0]) - elif target_region[1]: - yield(name[0], parent_region[0], target_region[1]) - elif parent_region[1]: - if target_region[0] and not target_swapped: - yield(name[1], parent_region[1], target_region[0]) - elif target_region[1]: - yield(name[1], parent_region[1], target_region[1]) + for names, parent_regions, target_regions in boots_clips: + region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), True) + if region_pair and region_pair[2]: + assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + yield(region_pair[0], region_pair[1], region_pair[2]) + def get_boots_clip_exits_dw(world, player): """ @@ -164,21 +158,14 @@ def get_boots_clip_exits_dw(world, player): """ for name, parent_region, target_region in boots_clips_local: - if world.is_tile_swapped(OWTileRegions[parent_region], player): + if not world.is_tile_lw_like(OWTileRegions[parent_region], player): yield(name, parent_region, target_region) - for name, parent_region, target_region in boots_clips: - parent_swapped, target_swapped = get_swapped_status(world, player, parent_region, target_region) - if parent_region[0] and parent_swapped: - if target_region[0] and target_swapped: - yield(name[0], parent_region[0], target_region[0]) - elif target_region[1]: - yield(name[0], parent_region[0], target_region[1]) - elif parent_region[1]: - if target_region[0] and target_swapped: - yield(name[1], parent_region[1], target_region[0]) - elif target_region[1]: - yield(name[1], parent_region[1], target_region[1]) + for names, parent_regions, target_regions in boots_clips: + region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), False) + if region_pair and region_pair[2]: + assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + yield(region_pair[0], region_pair[1], region_pair[2]) def get_glitched_speed_drops_lw(world, player): @@ -198,21 +185,14 @@ def get_mirror_clip_spots(world, player): """ for name, parent_region, target_region in mirror_clips_local: - if not world.is_tile_swapped(OWTileRegions[parent_region], player): + if not world.is_tile_lw_like(OWTileRegions[parent_region], player): yield(name, parent_region, target_region) - for name, parent_region, target_region in mirror_clips: - parent_swapped, target_swapped = get_swapped_status(world, player, parent_region, target_region) - if parent_region[0] and not parent_swapped: - if target_region[0] and not target_region: - yield(name[0], parent_region[0], target_region[0]) - elif target_region[1]: - yield(name[0], parent_region[0], target_region[1]) - elif parent_region[1]: - if target_region[0] and not target_region: - yield(name[1], parent_region[1], target_region[0]) - elif target_region[1]: - yield(name[1], parent_region[1], target_region[1]) + for names, parent_regions, target_regions in mirror_clips: + region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), False) + if region_pair and region_pair[2] and not world.is_tile_lw_like(OWTileRegions[region_pair[1]], player): + assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + yield(region_pair[0], region_pair[1], region_pair[2]) def get_mirror_offset_spots(world, player): @@ -222,19 +202,11 @@ def get_mirror_offset_spots(world, player): # TODO: These really should check to see if there is a mirrorless path to the mirror portal # but being that OWG is very very open, it's very unlikely there isn't a path, but possible - - for name, parent_region, target_region, path_to in mirror_offsets: - parent_swapped, target_swapped = get_swapped_status(world, player, parent_region, target_region) - if parent_region[0] and not parent_swapped: - if target_region[0] and not target_region: - yield(name[0], parent_region[0], target_region[0]) - elif target_region[1]: - yield(name[0], parent_region[0], target_region[1]) - elif parent_region[1]: - if target_region[0] and not target_region: - yield(name[1], parent_region[1], target_region[0]) - elif target_region[1]: - yield(name[1], parent_region[1], target_region[1]) + for names, parent_regions, target_regions, path_to in mirror_offsets: + region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions, path_to), False) + if region_pair and region_pair[2] and not world.is_tile_lw_like(OWTileRegions[region_pair[1]], player): + assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + yield(region_pair[0], region_pair[1], region_pair[2], region_pair[3]) def get_swapped_status(world, player, parents, targets): @@ -252,7 +224,43 @@ def get_swapped_status(world, player, parents, targets): target_swapped = world.is_tile_swapped(OWTileRegions[targets[1]], player) return parent_swapped, target_swapped - + + +def get_region_pairs(world, player, names, parent_regions, target_regions, path_regions=None): + # this pairs the source region to the proper destination + region_pairs = [None, None] + parent_swapped, target_swapped = get_swapped_status(world, player, parent_regions, target_regions) + if parent_regions[0]: + region_pairs[0] = [names[0], parent_regions[0]] + if parent_swapped == target_swapped: + region_pairs[0].append(target_regions[0]) + if path_regions: + region_pairs[0].append(path_regions[0]) + else: + region_pairs[0].append(target_regions[1]) + if path_regions: + region_pairs[0][3] = path_regions[1] + if parent_regions[1]: + region_pairs[1] = [names[1], parent_regions[1]] + if parent_swapped == target_swapped: + region_pairs[1].append(target_regions[1]) + if path_regions: + region_pairs[1].append(path_regions[1]) + else: + region_pairs[1].append(target_regions[0]) + if path_regions: + region_pairs[1].append(path_regions[0]) + return region_pairs + + +def get_world_pair(world, player, region_pairs, get_light_world): + # this chooses the region pair that is in the right world + if ((region_pairs[0] and world.is_tile_lw_like(OWTileRegions[region_pairs[0][1]], player)) \ + or not world.is_tile_lw_like(OWTileRegions[region_pairs[1][1]], player)) == get_light_world: + return region_pairs[0] + else: + return region_pairs[1] + def create_owg_connections(world, player): """ @@ -267,7 +275,10 @@ def create_owg_connections(world, player): # Mirror clip spots. create_no_logic_connections(player, world, get_mirror_clip_spots(world, player)) - create_no_logic_connections(player, world, get_mirror_offset_spots(world, player)) + + # Mirror offset spots. + for data in get_mirror_offset_spots(world, player): + create_no_logic_connections(player, world, [data[0:3]]) def overworld_glitches_rules(world, player): @@ -281,7 +292,10 @@ def overworld_glitches_rules(world, player): # Mirror clip spots. set_owg_rules(player, world, get_mirror_clip_spots(world, player), lambda state: state.has_Mirror(player)) - set_owg_rules(player, world, get_mirror_offset_spots(world, player), lambda state: state.has_Mirror(player) and state.can_boots_clip_lw(player)) + + # Mirror offset spots. + for data in get_mirror_offset_spots(world, player): + set_owg_rules(player, world, [data[0:3]], lambda state: state.has_Mirror(player) and state.can_boots_clip_lw(player) and state.can_reach(data[3], None, player)) # Regions that require the boots and some other stuff. # TODO: Revisit below when we can guarantee water walk @@ -297,12 +311,7 @@ def overworld_glitches_rules(world, player): add_additional_rule(world.get_entrance('VoO To Dig Game Hook Clip', player), lambda state: state.has('Hookshot', player)) add_additional_rule(world.get_entrance('Tree Line Water Clip', player), lambda state: state.has('Flippers', player)) add_additional_rule(world.get_entrance('Dark Tree Line Water Clip', player), lambda state: state.has('Flippers', player)) - if not world.is_tile_swapped(0x33, player): - add_additional_rule(world.get_entrance('South Teleporter Cliff Ledge Drop', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - world.get_entrance('Dark South Teleporter Cliff Ledge Drop', player).access_rule = lambda state: False - else: - add_additional_rule(world.get_entrance('Dark South Teleporter Cliff Ledge Drop', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - world.get_entrance('South Teleporter Cliff Ledge Drop', player).access_rule = lambda state: False + def add_alternate_rule(entrance, rule): old_rule = entrance.access_rule @@ -315,7 +324,7 @@ def add_additional_rule(entrance, rule): def create_no_logic_connections(player, world, connections): - for entrance, parent_region, target_region, *rule_override in connections: + for entrance, parent_region, target_region, *_ in connections: parent = world.get_region(parent_region, player) target = world.get_region(target_region, player) connection = Entrance(player, entrance, parent) @@ -325,7 +334,7 @@ def create_no_logic_connections(player, world, connections): def set_owg_rules(player, world, connections, default_rule): - for entrance, parent_region, target_region, *rule_override in connections: + for entrance, _, _, *rule_override in connections: connection = world.get_entrance(entrance, player) rule = rule_override[0] if len(rule_override) > 0 else default_rule connection.access_rule = rule @@ -463,7 +472,7 @@ boots_clips = [ (['C Whirlpool To Cliff Clip', 'Dark C Whirlpool To Cliff Clip'], ['C Whirlpool Area', 'Dark C Whirlpool Area'], ['Central Cliffs', 'Dark Central Cliffs']), (['C Whirlpool Outer To Cliff Clip', 'Dark C Whirlpool Outer To Cliff Clip'], ['C Whirlpool Outer Area', 'Dark C Whirlpool Outer Area'], ['Central Cliffs', 'Dark Central Cliffs']), - (['South Teleporter Cliff Ledge Drop', 'Dark South Teleporter Cliff Ledge Drop'], ['C Whirlpool Area', 'Dark C Whirlpool Area'], ['Dark Central Cliffs', 'Central Cliffs']), # glove/pearl + (['C Whirlpool Portal Bomb Clip', 'Dark C Whirlpool Portal Bomb Clip'], ['C Whirlpool Portal Area', 'Dark C Whirlpool Portal Area'], ['Central Cliffs', 'Dark Central Cliffs']), # bomb TODO: bombbag not considered (['Statues To Cliff Clip', 'Hype To Cliff Clip'], ['Statues Area', 'Hype Cave Area'], ['Central Cliffs', 'Dark Central Cliffs']), @@ -495,6 +504,6 @@ mirror_clips = [ ] mirror_offsets = [ - (['DM Offset Mirror', 'DDM Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Courtyard', 'Pyramid Area'], ['Pyramid Area', 'Hyrule Castle Courtyard']), - (['DM To HC Ledge Offset Mirror', 'DDM To HC Ledge Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', None], ['Pyramid Area', None]) + (['DM Offset Mirror', 'DDM Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', 'Pyramid Crack'], ['Pyramid Area', 'Hyrule Castle Courtyard']) + #(['DM To HC Ledge Offset Mirror', 'DDM To HC Ledge Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', None], ['Pyramid Area', None]) ] \ No newline at end of file From 5316885d465eaaa6a2eb465ec4483342edd391fb Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 14:37:04 -0600 Subject: [PATCH 11/17] Fixed OWG logic to apply logic in correct world --- BaseClasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BaseClasses.py b/BaseClasses.py index c645ce8d..287c0a02 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -316,6 +316,9 @@ class World(object): def is_tile_swapped(self, owid, player): return (self.mode[player] == 'inverted') != (owid in self.owswaps[player][0] and self.owMixed[player]) + def is_tile_lw_like(self, owid, player): + return (owid >= 0x40 and owid < 0x80) == self.is_tile_swapped(owid, player) + def is_atgt_swapped(self, player): return self.is_tile_swapped(0x03, player) and self.is_tile_swapped(0x1b, player) From d572db1233b74e7461a05d60842c7b8c1f358a14 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 14:38:21 -0600 Subject: [PATCH 12/17] Remodeled Pyramid Crack/Fairy to allow OWG entry --- BaseClasses.py | 2 +- Regions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 287c0a02..922eab75 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1538,7 +1538,7 @@ class Entrance(object): def can_reach(self, state): # Destination Pickup OW Only No Ledges Can S&Q Allow Mirror - multi_step_locations = { 'Pyramid Crack': ('Big Bomb', True, True, False, True), + multi_step_locations = { 'Pyramid Area': ('Big Bomb', True, True, False, True), 'Missing Smith': ('Frog', True, False, True, True), 'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True, True), 'Old Man Drop Off': ('Lost Old Man', True, False, False, False), diff --git a/Regions.py b/Regions.py index 9208094a..7f7d025d 100644 --- a/Regions.py +++ b/Regions.py @@ -173,8 +173,8 @@ def create_regions(world, player): create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Kakariko Grass Mirror Spot']), create_dw_region(player, 'Shield Shop Area', None, ['Shield Shop Fence (Outer) Ledge Drop', 'Forgotton Forest Mirror Spot', 'Shield Shop NW', 'Shield Shop NE']), create_dw_region(player, 'Shield Shop Fence', None, ['Shield Shop Fence (Inner) Ledge Drop', 'Red Shield Shop', 'Forgotton Forest Fence Mirror Spot']), - create_dw_region(player, 'Pyramid Area', ['Pyramid'], ['Pyramid Fairy', 'Pyramid Crack', 'Pyramid Hole', 'HC Ledge Mirror Spot', 'HC Courtyard Mirror Spot', 'HC Area Mirror Spot', 'HC East Entry Mirror Spot', 'Pyramid ES']), - create_dw_region(player, 'Pyramid Crack', ['Pyramid Crack'], None), + create_dw_region(player, 'Pyramid Area', ['Pyramid Crack', 'Pyramid'], ['Pyramid Crack', 'Pyramid Hole', 'HC Ledge Mirror Spot', 'HC Courtyard Mirror Spot', 'HC Area Mirror Spot', 'HC East Entry Mirror Spot', 'Pyramid ES']), + create_dw_region(player, 'Pyramid Crack', None, ['Pyramid Fairy']), create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Exit Ledge Drop', 'HC Courtyard Left Mirror Spot', 'Pyramid Entrance']), create_dw_region(player, 'Pyramid Pass', None, ['Post Aga Inverted Teleporter', 'HC Area South Mirror Spot', 'Pyramid SW', 'Pyramid SE']), create_dw_region(player, 'Pyramid Water', None, ['Hammerpegs Water Exit', 'Big Bomb Shop Water Exit'], 'Dark World', Terrain.Water), From a646fcd25a27ca6bf875a12d52cc6d789cb477fb Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 15:22:42 -0600 Subject: [PATCH 13/17] Fixed OWG logic to apply logic in correct world --- OverworldGlitchRules.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 0c705028..61636737 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -255,8 +255,12 @@ def get_region_pairs(world, player, names, parent_regions, target_regions, path_ def get_world_pair(world, player, region_pairs, get_light_world): # this chooses the region pair that is in the right world - if ((region_pairs[0] and world.is_tile_lw_like(OWTileRegions[region_pairs[0][1]], player)) \ - or not world.is_tile_lw_like(OWTileRegions[region_pairs[1][1]], player)) == get_light_world: + if region_pairs[0]: + is_lw = world.is_tile_lw_like(OWTileRegions[region_pairs[0][1]], player) + else: + is_lw = not world.is_tile_lw_like(OWTileRegions[region_pairs[1][1]], player) + + if is_lw == get_light_world: return region_pairs[0] else: return region_pairs[1] From 81def0dee8f07b56549b67b851a2bad160985c29 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 16:00:17 -0600 Subject: [PATCH 14/17] Fixed indentation issues in Readme --- README.md | 74 +++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 93ad893e..f4a563d7 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ See https://alttpr.com/ for more details on the normal randomizer. This is a very new mode of LTTPR so the tools and info is very limited. - There is an [OW Rando Cheat Sheet](https://zelda.codemann8.com/images/shared/ow-rando-reference-sheet.png) that shows all the transitions that exist and are candidates for shuffle. - There is OW tracking capability within the following trackers: - - [Community Tracker](https://alttptracker.dunka.net/) - - CodeTracker, an [EmoTracker](https://emotracker.net) package for LTTPR + - [Community Tracker](https://alttptracker.dunka.net/) + - CodeTracker, an [EmoTracker](https://emotracker.net) package for LTTPR - There is an [OW OWG Reference Sheet](https://zelda.codemann8.com/images/shared/ow-owg-reference-sheet.png) that shows all the in-logic places where boots/mirror clips and fake flippers are expected from the player. # Known Issues @@ -30,15 +30,15 @@ All feedback and dev conversation happens in the #ow-rando channel on the [ALTTP # Installation from Source -1) Download the source code from the repository directly and put it in a folder of your choosing. +1. Download the source code from the repository directly and put it in a folder of your choosing. -2) You must have Python installed (version 3.7 - 3.10 supported), and ensure PATH is included during the installation. +2. You must have Python installed (version 3.7 - 3.10 supported), and ensure PATH is included during the installation. -3) This program requires all python dependencies that are necessary to run OW Randomizer. There are multiple ways to install them: - - Try running ```pip install missingdependency``` or ```python -m pip install missingdependency``` on the command line (replace ```missingdependency``` with the specific package that is missing) to install the dependency. - - The simpler method, run (double-click) ```resources/ci/common/local_install.py``` to install all the missing dependencies as well. +3. This program requires all python dependencies that are necessary to run OW Randomizer. There are multiple ways to install them: + - Try running ```pip install missingdependency``` or ```python -m pip install missingdependency``` on the command line (replace ```missingdependency``` with the specific package that is missing) to install the dependency. + - The simpler method, run (double-click) ```resources/ci/common/local_install.py``` to install all the missing dependencies as well. -4) Once installed, you should be able to run (double-click) ```Gui.py``` and the OWR program will appear, where you can select your desired settings. +4. Once installed, you should be able to run (double-click) ```Gui.py``` and the OWR program will appear, where you can select your desired settings. See the following link if you have additional trouble: https://github.com/codemann8/ALttPDoorRandomizer/blob/OverworldShuffle/docs/BUILDING.md @@ -61,18 +61,18 @@ OWR definitely has a lot of options, and all of them by themselves are pretty si ## "Any recommendations for a first-timer?" For a first (and second) seed... *and I say "second" because I feel like both of these recommendations I'm about to make have VERY different vibes, have different levels of challenge, but are both, of their own right, worthy of being tried at least once.* Your first OWR experience can be combined with any mode combination that you are already familiar with and have a lot of experience in playing. If you like Crosskeys and feel very comfortable running that, feel free to turn on all those settings in addition to ONE of these two options: 1. `OW Tile Flip (Mixed)` - Overly, a pretty easy-breezy mode, it doesn't require too much big brain, and is pretty managable even without proper logic tracking, as long as you at least have a standard map tracker. This is actually my favorite way to run OWR today - - DO NOT turn on Layout or Whirlpool Shuffle, leave this on `Vanilla` - - DO NOT turn on Crossed OWR - - `Flute Shuffle` or `Bonk Drops` could be enabled if desired, altho I'd recommend against it, at least for a fresh viewpoint of Mixed OWR + - DO NOT turn on Layout or Whirlpool Shuffle, leave this on `Vanilla` + - DO NOT turn on Crossed OWR + - `Flute Shuffle` or `Bonk Drops` could be enabled if desired, altho I'd recommend against it, at least for a fresh viewpoint of Mixed OWR 2. `OW Layout Shuffle` - Set to `Parallel`. This is the original spirit and vision of OWR from the time of its own founding. It's definitely much more complicated to run than OW Tile Flip, so keep that in mind. - - `Starting Boots` - Either actual boots or pseudoboots, you will be spending a lot of time navigating the OW, so it's best to do it with the ability to run fast. - - DO NOT turn on OW Tile Flip (Mixed) - - DO NOT turn on Crossed OWR - - Enable `Whirlpool Shuffle` - Recommended to always be enabled with Layout Shuffle - - Enable `Keep Similar Edges Together` - This just helps keep some of your sanity for a first experience - - Enable `Flute Shuffle` - I recommend setting this to `Balanced`, this helps space out the flute spots across the world. Being that the world itself is shuffled, the vanilla flute spots are likely NOT as conveniently located as they normally are. - - `Free Terrain` - Recommend to NOT turn this on for a first run, but definitely on a second run. - - `Bonk Drops` - Recommend to NOT turn this on, especially if you don't have starting boots, but you could enable this in future seeds if you've become more familiar with OWR, as you'll be visiting these screens anyways, you might as well grab the items on the way :) + - `Starting Boots` - Either actual boots or pseudoboots, you will be spending a lot of time navigating the OW, so it's best to do it with the ability to run fast. + - DO NOT turn on OW Tile Flip (Mixed) + - DO NOT turn on Crossed OWR + - Enable `Whirlpool Shuffle` - Recommended to always be enabled with Layout Shuffle + - Enable `Keep Similar Edges Together` - This just helps keep some of your sanity for a first experience + - Enable `Flute Shuffle` - I recommend setting this to `Balanced`, this helps space out the flute spots across the world. Being that the world itself is shuffled, the vanilla flute spots are likely NOT as conveniently located as they normally are. + - `Free Terrain` - Recommend to NOT turn this on for a first run, but definitely on a second run. + - `Bonk Drops` - Recommend to NOT turn this on, especially if you don't have starting boots, but you could enable this in future seeds if you've become more familiar with OWR, as you'll be visiting these screens anyways, you might as well grab the items on the way :) ## "What tracker should I use?" I personally use 2 trackers together, at least if Layout Shuffle is enabled. Currently, DunkaTracker is the ONLY tracker that is useful for tracking Layout Shuffle, can highly recommend. However, I personally don't like the main portion of the tracker and ignore the main window completely. For tracking everything else, I use `CodeTracker`, a tracker pack that is installable within `EmoTracker`, this handles ALL OWR modes EXCEPT Layout Shuffle (and generally Crossed OW, but missing that doesn't make much of a difference). I am unaware of ANY trackers outside of these 2 that handle OWR modes, so my advice would be to familiarize yourself with both trackers and pick and choose the parts you find most useful for yourself. @@ -201,8 +201,8 @@ Tile Flip (often referred to as Mixed OWR) can be thought of as a hybrid of Open Being that this uses concepts from Inverted, it will be important to review the OWR-exclusive changes that have been made to Inverted (often referred to as Inverted 2.0). See `Inverted Changes` for more details. During gameplay: - - When on the OW, there will be an L or D in the upper left corner, indicating which world you are currently in. Mirroring still works the same, you must be in the DW to mirror to the LW. - - When doing a map check (pressing X while on the OW), the tiles shown will reflect the flipped tiles. This means that dungeon prizes will show the prizes for the dungeons that are now part of that world, beware of Desert/Mire and Eastern/PoD. Here is an image showing the difference of appearance when tiles are flipped on the [map check](https://media.discordapp.net/attachments/783989090017738753/970646558049714196/lttp-lw-mapcheck.gif) screen. + - When on the OW, there will be an L or D in the upper left corner, indicating which world you are currently in. Mirroring still works the same, you must be in the DW to mirror to the LW. + - When doing a map check (pressing X while on the OW), the tiles shown will reflect the flipped tiles. This means that dungeon prizes will show the prizes for the dungeons that are now part of that world, beware of Desert/Mire and Eastern/PoD. Here is an image showing the difference of appearance when tiles are flipped on the [map check](https://media.discordapp.net/attachments/783989090017738753/970646558049714196/lttp-lw-mapcheck.gif) screen. Note: Tiles are put into Tile Groups (see `Terminology`) that must be shuffled together when certain settings are enabled. For instance, if ER is disabled, then any tiles that have a connector cave that leads to a different tile, then those tiles must flip together. @@ -210,14 +210,14 @@ Note: Tiles are put into Tile Groups (see `Terminology`) that must be shuffled t The above OWR options are very difficult to describe. The above descriptions are written in a way that is most correct even when these options are combined with more complicated modes. But, this section aims to simplify the explanation by assuming the user chooses a normal 'Open 7/7 Defeat Ganon' seed but with just one OWR setting enabled. Both of these options are very similar and often confused from each other. -- Tile Flip is a mode where some DW tiles are moved and BECOME part of the LW (and the LW counterparts become part of the DW). What does it mean to "become" part of a world? It means that it will inherit (NOT bring over) the properties of that world it is moving to (such as being able to flute, ability to use the mirror, or being susceptible to bunnying). -- Crossed on the other hand doesn't change the properties of tiles, instead it transports Link *physically?* across worlds upon transitioning. This also means that Link can be transformed into a bunny moving from tile to tile. + - Tile Flip is a mode where some DW tiles are moved and BECOME part of the LW (and the LW counterparts become part of the DW). What does it mean to "become" part of a world? It means that it will inherit (NOT bring over) the properties of that world it is moving to (such as being able to flute, ability to use the mirror, or being susceptible to bunnying). + - Crossed on the other hand doesn't change the properties of tiles, instead it transports Link *physically?* across worlds upon transitioning. This also means that Link can be transformed into a bunny moving from tile to tile. tldr: Tile Flip moves the tiles, Crossed moves Link So, let's run an example of 2 tiles, Link's House and the screen to the right of it. Transitioning right from Link's House: In vanilla, you get the Stone Bridge screen and Link stays his normal self and is just normal LW behavior. Now, let's assume Links House screen stays vanilla, but the tile to the right is getting Flipped or Crossed. -- In Tile Flip, you'd get the Hammer Bridge screen and Link would stay as Link and you'd be able to flute away from this screen if you had a flute. -- In Crossed, you'd get the same Hammer Bridge Screen, but this time Link would be transformed into a bunny, just like he'd normally be when on that tile. -- In Polar Crossed (when both Tile Flip and Crossed effects are applied together), you get the normal Stone Bridge screen, but Link is transformed to a bunny (because the Stone Bridge screen has moved to the DW AND Link is also moving across worlds). + - In Tile Flip, you'd get the Hammer Bridge screen and Link would stay as Link and you'd be able to flute away from this screen if you had a flute. + - In Crossed, you'd get the same Hammer Bridge Screen, but this time Link would be transformed into a bunny, just like he'd normally be when on that tile. + - In Polar Crossed (when both Tile Flip and Crossed effects are applied together), you get the normal Stone Bridge screen, but Link is transformed to a bunny (because the Stone Bridge screen has moved to the DW AND Link is also moving across worlds). As you can see, things get pretty complicated when mixing modes together. Doing this can definitely create a very unique and interesting experience, but one that is very hard to grasp. And then beyond that there is OW Layout Shuffle, which is where transition destinations are shuffled, so Link will get transported to a different tile entirely, but the same rules apply when you eventually find the Stone/Hammer Bridge screen, you just likely won't find that screen thru a transition on Link's House screen. @@ -248,17 +248,17 @@ New flute spots are chosen at random with minimum bias. This adds 41 new item locations to the game. These bonk locations are limited to the ones that drop a static item in the vanilla game. - Bonk Locations consist of some trees, rocks, and statues - - 33 Trees - - 8 of the tree locations require Agahnim to be defeated to access the item - - 6 Rocks - - 1 of the rocks drops 2 items - - 1 Statue + - 33 Trees + - 8 of the tree locations require Agahnim to be defeated to access the item + - 6 Rocks + - 1 of the rocks drops 2 items + - 1 Statue - Bonk locations can be collected by bonking into them with the Pegasus Boots or using the Quake Medallion - One of the bonk locations are guaranteed to have a full magic decanter - Some of the drops can be farmed repeatedly, but only increments the collection rate once - All of the bonk trees have been given an alternate color (and all non-bonk trees are reverted to normal tree color) - - Some screens are coded to change the "alternate tree color", some of them are strange (just how the vanilla game does it) - - Rocks and statues are unable to be made to have a different color + - Some screens are coded to change the "alternate tree color", some of them are strange (just how the vanilla game does it) + - Rocks and statues are unable to be made to have a different color - Since Fairies and Apples are new items that can appear in plain sight, they don't have a proper graphic for them yet. For now, they show up as Power Stars Here is a map that shows all the [Bonk Locations](https://media.discordapp.net/attachments/783989090017738753/1000880877548609607/unknown.png?width=1399&height=702). FYI, the 2-4 and 2-3-4 refer to the tree numbers that have the items. The 2 by Dark Fortune Teller indicate that there are 2 bonk items there. The stars with a green square are all Bonk Locations that are unlocked after you kill Aga 1. @@ -293,8 +293,8 @@ This mode is intended to be a beginner-friendly introduction to playing ER, unli This mode groups entrances into types and shuffles them freely within those groups. - Dungeons and Connectors (Multi-Entrance Caves) - Item Locations (Single-Entrance Caves with an item, includes Potion Shop and Red Bomb Shop) - - Includes Shops only if Shopsanity is enabled - - Includes caves with pots only if Pottery settings have them shuffled) + - Includes Shops only if Shopsanity is enabled + - Includes caves with pots only if Pottery settings have them shuffled) - Dropdowns and their associated exits (Skull Woods dropdowns are handled the same as in Crossed) - Non-item locations (junk locations) all remain vanilla @@ -322,8 +322,8 @@ This mode is intended to be a more refined and more competitive format to Crosse This mode groups entrances into types and shuffles them freely within those groups. - Dungeons and Connectors (Multi-Entrance Caves) - Item Locations (Single-Entrance Caves with an item, includes Potion Shop and Red Bomb Shop) - - Includes Shops only if Shopsanity is enabled - - Includes caves with pots only if Pottery settings have them shuffled) + - Includes Shops only if Shopsanity is enabled + - Includes caves with pots only if Pottery settings have them shuffled) - Dropdowns and their associated exits (Skull Woods dropdowns are handled the same as in Crossed) - Non-item locations (junk locations) all remain vanilla From b9bbd5fcd673e6b309b01f78fb112825bb336d37 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 16:10:58 -0600 Subject: [PATCH 15/17] Added improvements to installation steps for simplicity --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f4a563d7..a1a09304 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,9 @@ All feedback and dev conversation happens in the #ow-rando channel on the [ALTTP # Installation from Source -1. Download the source code from the repository directly and put it in a folder of your choosing. +1. Download the source code from the repository directly and put it in a folder of your choosing. Any method of grabbing the source code is fine, but due to some changes on GitHub's site, some of the other alternatives might be better options for some people. + - Use [GitHub Desktop](https://desktop.github.com) to clone this repository to a folder on your computer. Once a repository is established, you can click `Fetch origin` or `Pull` to re-download whenever you want to grab the latest version. This is the best option for a simple one-click solution. + - Download the [source code](https://github.com/codemann8/ALttPDoorRandomizer/archive/refs/heads/OverworldShuffle.zip) from GitHub manually. 2. You must have Python installed (version 3.7 - 3.10 supported), and ensure PATH is included during the installation. From acbe38fbec734e3403eeac1bba78284f7994fede Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 16:27:02 -0600 Subject: [PATCH 16/17] Added improvements to installation steps for simplicity --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a1a09304..33807afe 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ All feedback and dev conversation happens in the #ow-rando channel on the [ALTTP - Use [GitHub Desktop](https://desktop.github.com) to clone this repository to a folder on your computer. Once a repository is established, you can click `Fetch origin` or `Pull` to re-download whenever you want to grab the latest version. This is the best option for a simple one-click solution. - Download the [source code](https://github.com/codemann8/ALttPDoorRandomizer/archive/refs/heads/OverworldShuffle.zip) from GitHub manually. -2. You must have Python installed (version 3.7 - 3.10 supported), and ensure PATH is included during the installation. +2. You must have [Python](https://www.python.org/downloads) installed (version 3.7 - 3.10 supported), and ensure PATH is included during the installation. + - A common issue with users is that there are multiple instances of Python installed on the same computer. This causes the computer to be confused with which Python instance it uses. Ensure that any older Python installations have been removed. 3. This program requires all python dependencies that are necessary to run OW Randomizer. There are multiple ways to install them: - Try running ```pip install missingdependency``` or ```python -m pip install missingdependency``` on the command line (replace ```missingdependency``` with the specific package that is missing) to install the dependency. From ba95ae3903355d46a8df6c73d97d60b4cdcb546d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 28 Nov 2022 16:27:16 -0600 Subject: [PATCH 17/17] Version bump 0.2.11.4 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e03485c..e5301933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.2.11.4 +- Fixed broken OWG logic issues +- Gave chickens a base price for shopsanity +- Modeled TR entrance opening to use a logical pseudo-item + ## 0.2.11.3 - Fixed error during multiworld generation - Added proper Old Man pathing to the logic and spoiler playthru diff --git a/OverworldShuffle.py b/OverworldShuffle.py index c6be3b90..fe981f78 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.2.11.3' +version_number = '0.2.11.4' # branch indicator is intentionally different across branches version_branch = '-u'