Merge branch 'KrisDavie-hmg_logic' into DoorDevVolatile
This commit is contained in:
@@ -133,7 +133,7 @@ class World(object):
|
||||
set_player_attr('can_access_trock_front', None)
|
||||
set_player_attr('can_access_trock_big_chest', None)
|
||||
set_player_attr('can_access_trock_middle', None)
|
||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'nologic']
|
||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'hybridglitches', 'nologic']
|
||||
or shuffle[player] in ['lean', 'swapped', 'crossed', 'insanity'])
|
||||
set_player_attr('mapshuffle', False)
|
||||
set_player_attr('compassshuffle', False)
|
||||
@@ -603,6 +603,42 @@ class CollectionState(object):
|
||||
self.placing_items = None
|
||||
# self.trace = None
|
||||
|
||||
def can_reach_from(self, spot, start, player=None):
|
||||
old_state = self.copy()
|
||||
# old_state.path = {old_state.world.get_region(start, player)}
|
||||
old_state.stale[player] = False
|
||||
old_state.reachable_regions[player] = dict()
|
||||
old_state.blocked_connections[player] = dict()
|
||||
rrp = old_state.reachable_regions[player]
|
||||
bc = old_state.blocked_connections[player]
|
||||
|
||||
# init on first call - this can't be done on construction since the regions don't exist yet
|
||||
start = self.world.get_region(start, player)
|
||||
if start in self.reachable_regions[player]:
|
||||
rrp[start] = self.reachable_regions[player][start]
|
||||
for conn in start.exits:
|
||||
bc[conn] = self.blocked_connections[player][conn]
|
||||
else:
|
||||
rrp[start] = CrystalBarrier.Orange
|
||||
for conn in start.exits:
|
||||
bc[conn] = CrystalBarrier.Orange
|
||||
|
||||
queue = deque(old_state.blocked_connections[player].items())
|
||||
|
||||
old_state.traverse_world(queue, rrp, bc, player)
|
||||
if old_state.world.key_logic_algorithm[player] == 'default':
|
||||
unresolved_events = [x for y in old_state.reachable_regions[player] for x in y.locations
|
||||
if x.event and x.item and (x.item.smallkey or x.item.bigkey or x.item.advancement)
|
||||
and x not in old_state.locations_checked and x.can_reach(old_state)]
|
||||
unresolved_events = old_state._do_not_flood_the_keys(unresolved_events)
|
||||
if len(unresolved_events) == 0:
|
||||
old_state.check_key_doors_in_dungeons(rrp, player)
|
||||
|
||||
if self.world.get_region(spot, player) in rrp:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def update_reachable_regions(self, player):
|
||||
self.stale[player] = False
|
||||
rrp = self.reachable_regions[player]
|
||||
@@ -1020,7 +1056,7 @@ class CollectionState(object):
|
||||
# try to resolve a name
|
||||
if resolution_hint == 'Location':
|
||||
spot = self.world.get_location(spot, player)
|
||||
elif resolution_hint in ['Entrance', 'OWEdge', 'OWTerrain', 'Ledge', 'Portal', 'Whirlpool', 'Mirror', 'Flute']:
|
||||
elif resolution_hint in ['Entrance', 'OWEdge', 'OWTerrain', 'OpenTerrain', 'Ledge', 'OWG', 'Portal', 'Whirlpool', 'Mirror', 'Flute']:
|
||||
spot = self.world.get_entrance(spot, player)
|
||||
else:
|
||||
# default to Region
|
||||
@@ -1169,6 +1205,12 @@ class CollectionState(object):
|
||||
def can_lift_rocks(self, player):
|
||||
return self.has('Power Glove', player) or self.has('Titans Mitts', player)
|
||||
|
||||
def can_bomb_clip(self, region, player: int) -> bool:
|
||||
return self.is_not_bunny(region, player) and self.has('Pegasus Boots', player) and self.can_use_bombs(player)
|
||||
|
||||
def can_dash_clip(self, region, player: int) -> bool:
|
||||
return self.is_not_bunny(region, player) and self.has('Pegasus Boots', player)
|
||||
|
||||
def has_bottle(self, player):
|
||||
return self.bottle_count(player) > 0
|
||||
|
||||
@@ -1348,6 +1390,9 @@ class CollectionState(object):
|
||||
def can_superbunny_mirror_with_sword(self, player):
|
||||
return self.has_Mirror(player) and self.has_sword(player)
|
||||
|
||||
def can_bunny_pocket(self, player):
|
||||
return self.has_Boots(player) and (self.has_Mirror(player) or self.has_bottle(player))
|
||||
|
||||
def collect(self, item, event=False, location=None):
|
||||
if location:
|
||||
self.locations_checked.add(location)
|
||||
@@ -1631,7 +1676,7 @@ class Entrance(object):
|
||||
if region not in explored_regions:
|
||||
explored_regions[region] = path
|
||||
for exit in region.exits:
|
||||
if exit.connected_region and (not ignore_ledges or exit.spot_type != 'Ledge') \
|
||||
if exit.connected_region and (not ignore_ledges or exit.spot_type not in ['Ledge', 'OWG']) \
|
||||
and exit.name not in ['Dig Game To Ledge Drop'] \
|
||||
and exit.access_rule(state):
|
||||
if exit.connected_region == destination:
|
||||
@@ -3422,7 +3467,7 @@ er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4,
|
||||
'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6, "swapped": 10}
|
||||
|
||||
# byte 1: LLLW WSS? (logic, mode, sword)
|
||||
logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4}
|
||||
logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4, "hybridglitches": 5}
|
||||
world_mode = {"open": 0, "standard": 1, "inverted": 2}
|
||||
sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3}
|
||||
|
||||
|
||||
@@ -814,7 +814,7 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player, must
|
||||
# Keeps track of entrances that cannot be used to access each exit / cave
|
||||
invalid_cave_connections = defaultdict(set)
|
||||
|
||||
# if world.logic[player] in ['owglitches', 'nologic']:
|
||||
# if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
# import OverworldGlitchRules
|
||||
# for entrance in OverworldGlitchRules.get_non_mandatory_exits(world, player):
|
||||
# if entrance in must_be_exits:
|
||||
|
||||
5
Fill.py
5
Fill.py
@@ -175,6 +175,9 @@ def valid_key_placement(item, location, key_pool, collection_state, world):
|
||||
if dungeon:
|
||||
if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name):
|
||||
return True
|
||||
# Small key and big key in Swamp and Hera are placed without logic
|
||||
if world.logic[item.player] == 'hybridglitches' and dungeon.name in ['Tower of Hera', 'Swamp Palace'] and dungeon.name in item.name:
|
||||
return True
|
||||
key_logic = world.key_logic[item.player][dungeon.name]
|
||||
unplaced_keys = len([x for x in key_pool if x.name == key_logic.small_key_name and x.player == item.player])
|
||||
prize_loc = None
|
||||
@@ -420,7 +423,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
|
||||
# fill in gtower locations with trash first
|
||||
for player in range(1, world.players + 1):
|
||||
if (not gftower_trash or not world.ganonstower_vanilla[player]
|
||||
or world.logic[player] in ['owglitches', 'nologic']):
|
||||
or world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']):
|
||||
continue
|
||||
gt_count, total_count = calc_trash_locations(world, player)
|
||||
scale_factor = .75 * (world.crystals_needed_for_gt[player] / 7)
|
||||
|
||||
13
ItemList.py
13
ItemList.py
@@ -327,6 +327,11 @@ def generate_itempool(world, player):
|
||||
for _ in range(0, amt):
|
||||
pool.append('Rupees (20)')
|
||||
|
||||
if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']:
|
||||
# In HMG force swamp smalls in pots to allow getting out of swamp palace
|
||||
placed_items['Swamp Palace - Trench 1 Pot Key'] = 'Small Key (Swamp Palace)'
|
||||
placed_items['Swamp Palace - Pot Row Pot Key'] = 'Small Key (Swamp Palace)'
|
||||
|
||||
start_inventory = list(world.precollected_items)
|
||||
for item in precollected_items:
|
||||
world.push_precollected(ItemFactory(item, player))
|
||||
@@ -1056,7 +1061,7 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt
|
||||
return random.choice([True, False]) if progressive == 'random' else progressive == 'on'
|
||||
|
||||
# provide boots to boots glitch dependent modes
|
||||
if logic in ['owglitches', 'nologic']:
|
||||
if logic in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
precollected_items.append('Pegasus Boots')
|
||||
pool.remove('Pegasus Boots')
|
||||
pool.extend(['Rupees (20)'])
|
||||
@@ -1362,12 +1367,12 @@ def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer
|
||||
|
||||
start_inventory = [x for x in world.precollected_items if x.player == player]
|
||||
if not start_inventory:
|
||||
if world.logic[player] in ['owglitches', 'nologic']:
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic'] and all(x.name != 'Pegasus Boots' for x in start_inventory):
|
||||
precollected_items.append('Pegasus Boots')
|
||||
if 'Pegasus Boots' in pool:
|
||||
pool.remove('Pegasus Boots')
|
||||
pool.append('Rupees (20)')
|
||||
if world.swords[player] == 'assured':
|
||||
if world.swords[player] == 'assured' and all(' Sword' not in x.name for x in start_inventory):
|
||||
precollected_items.append('Progressive Sword')
|
||||
if 'Progressive Sword' in pool:
|
||||
pool.remove('Progressive Sword')
|
||||
@@ -1503,7 +1508,7 @@ def make_customizer_pool(world, player):
|
||||
sphere_0 = world.customizer.get_start_inventory()
|
||||
no_start_inventory = not sphere_0 or not sphere_0[player]
|
||||
init_equip = [] if no_start_inventory else sphere_0[player]
|
||||
if (world.logic[player] in ['owglitches', 'nologic']
|
||||
if (world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']
|
||||
and (no_start_inventory or all(x != 'Pegasus Boots' for x in init_equip))):
|
||||
precollected_items.append('Pegasus Boots')
|
||||
if 'Pegasus Boots' in pool:
|
||||
|
||||
@@ -2106,6 +2106,22 @@ def validate_key_placement(key_layout, world, player):
|
||||
if i.player == player and i.name == smallkey_name:
|
||||
keys_outside += 1
|
||||
|
||||
if world.logic[player] == 'hybridglitches':
|
||||
# Swamp keylogic
|
||||
if smallkey_name.endswith('(Swamp Palace)'):
|
||||
swamp_entrance = world.get_location('Swamp Palace - Entrance', player)
|
||||
# Swamp small not vanilla
|
||||
if swamp_entrance.item is None or (swamp_entrance.item.name != smallkey_name or swamp_entrance.item.player != player):
|
||||
mire_keylayout = world.key_layout[player]['Misery Mire']
|
||||
mire_smallkey_name = dungeon_keys[mire_keylayout.sector.name]
|
||||
# Check if any mire keys are in swamp (excluding entrance), if none then add one to keys_outside
|
||||
mire_keys_in_swamp = sum([1 if x.item.name == mire_smallkey_name else 0 for x in key_layout.item_locations if x.item is not None and x != swamp_entrance])
|
||||
if mire_keys_in_swamp == 0:
|
||||
keys_outside +=1
|
||||
# Mire keylogic
|
||||
if smallkey_name.endswith('(Tower of Hera)'):
|
||||
# TODO: Make sure that mire medallion isn't in hera basement, or if it is, the small key is available downstairs
|
||||
big_key_outside = True
|
||||
for code, counter in key_layout.key_counters.items():
|
||||
if len(counter.child_doors) == 0:
|
||||
continue
|
||||
|
||||
23
Main.py
23
Main.py
@@ -28,6 +28,7 @@ from Fill import distribute_items_restrictive, promote_dungeon_items, fill_dunge
|
||||
from Fill import dungeon_tracking
|
||||
from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations, set_prize_drops
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops, fill_specific_items, create_farm_locations
|
||||
from UnderworldGlitchRules import create_hybridmajor_connections, create_hybridmajor_connectors
|
||||
from Utils import output_path, parse_player_names
|
||||
|
||||
from source.item.District import init_districts
|
||||
@@ -78,6 +79,11 @@ def main(args, seed=None, fish=None):
|
||||
seeded = True
|
||||
world.customizer.adjust_args(args)
|
||||
world = init_world(args, fish)
|
||||
|
||||
for i in zip(args.logic.values(), args.door_shuffle.values()):
|
||||
if i[0] == 'hybridglitches' and i[1] != 'vanilla':
|
||||
raise RuntimeError(BabelFish().translate("cli","cli","hybridglitches.door.shuffle"))
|
||||
|
||||
if seed is None:
|
||||
random.seed(None)
|
||||
world.seed = random.randint(0, 999999999)
|
||||
@@ -166,6 +172,8 @@ def main(args, seed=None, fish=None):
|
||||
create_dungeons(world, player)
|
||||
adjust_locations(world, player)
|
||||
place_bosses(world, player)
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connections(world, player)
|
||||
|
||||
if any(world.potshuffle.values()):
|
||||
logger.info(world.fish.translate("cli", "cli", "shuffling.pots"))
|
||||
@@ -191,6 +199,8 @@ def main(args, seed=None, fish=None):
|
||||
|
||||
for player in range(1, world.players + 1):
|
||||
link_entrances_new(world, player)
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connectors(world, player)
|
||||
|
||||
logger.info(world.fish.translate("cli", "cli", "shuffling.prep"))
|
||||
|
||||
@@ -594,8 +604,10 @@ def copy_world(world):
|
||||
for player in range(1, world.players + 1):
|
||||
create_regions(ret, player)
|
||||
update_world_regions(ret, player)
|
||||
if world.logic[player] in ('owglitches', 'nologic'):
|
||||
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
|
||||
create_owg_connections(ret, player)
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connections(ret, player)
|
||||
create_dynamic_exits(ret, player)
|
||||
create_dungeon_regions(ret, player)
|
||||
create_owedges(ret, player)
|
||||
@@ -703,6 +715,8 @@ def copy_world(world):
|
||||
for player in range(1, world.players + 1):
|
||||
categorize_world_regions(ret, player)
|
||||
create_farm_locations(ret, player)
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connectors(ret, player)
|
||||
set_rules(ret, player)
|
||||
|
||||
return ret
|
||||
@@ -782,8 +796,10 @@ def copy_world_premature(world, player):
|
||||
|
||||
create_regions(ret, player)
|
||||
update_world_regions(ret, player)
|
||||
if world.logic[player] in ('owglitches', 'nologic'):
|
||||
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
|
||||
create_owg_connections(ret, player)
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connections(ret, player)
|
||||
create_dynamic_exits(ret, player)
|
||||
create_dungeon_regions(ret, player)
|
||||
create_owedges(ret, player)
|
||||
@@ -844,6 +860,9 @@ def copy_world_premature(world, player):
|
||||
for portal in world.dungeon_portals[player]:
|
||||
connect_portal(portal, ret, player)
|
||||
|
||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||
create_hybridmajor_connectors(ret, player)
|
||||
|
||||
set_rules(ret, player)
|
||||
|
||||
return ret
|
||||
|
||||
49
OWEdges.py
49
OWEdges.py
@@ -1558,23 +1558,39 @@ OWExitTypes = {
|
||||
'Ice Lake Southeast Water Drop',
|
||||
'Bomber Corner Waterfall Water Drop'
|
||||
],
|
||||
'OWTerrain': ['Lost Woods Bush (West)',
|
||||
'Lost Woods Bush (East)',
|
||||
'Old Man Drop Off',
|
||||
'OpenTerrain': ['Old Man Drop Off',
|
||||
'Spectacle Rock Approach',
|
||||
'Spectacle Rock Leave',
|
||||
'DM Hammer Bridge (West)',
|
||||
'DM Hammer Bridge (East)',
|
||||
'Floating Island Bridge (East)',
|
||||
'Fairy Ascension Rocks (Inner)',
|
||||
'DM Broken Bridge (West)',
|
||||
'DM Broken Bridge (East)',
|
||||
'Spiral Mimic Bridge (West)',
|
||||
'Spiral Mimic Bridge (East)',
|
||||
'Spiral Ledge Approach',
|
||||
'Mimic Ledge Approach',
|
||||
'Fairy Ascension Rocks (Outer)',
|
||||
'Floating Island Bridge (West)',
|
||||
'Graveyard Ladder (Bottom)',
|
||||
'Graveyard Ladder (Top)',
|
||||
'Hyrule Castle Main Gate (South)',
|
||||
'Hyrule Castle Main Gate (North)',
|
||||
'Stone Bridge (Northbound)',
|
||||
'Stone Bridge (Southbound)',
|
||||
'Checkerboard Ledge Approach',
|
||||
'Checkerboard Ledge Leave',
|
||||
'Cave 45 Approach',
|
||||
'Cave 45 Leave',
|
||||
'Middle Aged Man',
|
||||
'Desert Pass Ladder (South)',
|
||||
'Desert Pass Ladder (North)',
|
||||
'GT Approach',
|
||||
'GT Leave',
|
||||
],
|
||||
'OWTerrain': ['Lost Woods Bush (West)',
|
||||
'Lost Woods Bush (East)',
|
||||
'DM Hammer Bridge (West)',
|
||||
'DM Hammer Bridge (East)',
|
||||
'Fairy Ascension Rocks (Inner)',
|
||||
'DM Broken Bridge (West)',
|
||||
'DM Broken Bridge (East)',
|
||||
'Fairy Ascension Rocks (Outer)',
|
||||
'TR Pegs Ledge Entry',
|
||||
'TR Pegs Ledge Leave',
|
||||
'Mountain Pass Rock (Outer)',
|
||||
@@ -1587,8 +1603,6 @@ OWExitTypes = {
|
||||
'Lost Woods Pass Rock (North)',
|
||||
'Lost Woods Pass Rock (South)',
|
||||
'Kings Grave Rocks (Outer)',
|
||||
'Graveyard Ladder (Bottom)',
|
||||
'Graveyard Ladder (Top)',
|
||||
'Kings Grave Rocks (Inner)',
|
||||
'River Bend Water Drop',
|
||||
'River Bend West Pier',
|
||||
@@ -1602,12 +1616,10 @@ OWExitTypes = {
|
||||
'Kakariko Yard Bush (South)',
|
||||
'Kakariko Southwest Bush (South)',
|
||||
'Kakariko Yard Bush (North)',
|
||||
'Hyrule Castle Main Gate (South)',
|
||||
'Hyrule Castle East Rock (Inner)',
|
||||
'Hyrule Castle Southwest Bush (North)',
|
||||
'Hyrule Castle Southwest Bush (South)',
|
||||
'Hyrule Castle Courtyard Bush (South)',
|
||||
'Hyrule Castle Main Gate (North)',
|
||||
'Hyrule Castle Courtyard Bush (North)',
|
||||
'Hyrule Castle East Rock (Outer)',
|
||||
'Wooden Bridge Bush (South)',
|
||||
@@ -1615,17 +1627,11 @@ OWExitTypes = {
|
||||
'Blacksmith Ledge Peg (West)',
|
||||
'Blacksmith Ledge Peg (East)',
|
||||
'Maze Race Game',
|
||||
'Stone Bridge (Northbound)',
|
||||
'Stone Bridge (Southbound)',
|
||||
'Desert Statue Move',
|
||||
'Checkerboard Ledge Approach',
|
||||
'Desert Ledge Rocks (Outer)',
|
||||
'Desert Ledge Rocks (Inner)',
|
||||
'Checkerboard Ledge Leave',
|
||||
'Flute Boy Bush (South)',
|
||||
'Cave 45 Approach',
|
||||
'Flute Boy Bush (North)',
|
||||
'Cave 45 Leave',
|
||||
'C Whirlpool Rock (Bottom)',
|
||||
'C Whirlpool Rock (Top)',
|
||||
'C Whirlpool Pegs (Outer)',
|
||||
@@ -1644,19 +1650,14 @@ OWExitTypes = {
|
||||
'Lake Hylia Water D Approach',
|
||||
'Lake Hylia Water D Leave',
|
||||
'Ice Cave Pier',
|
||||
'Desert Pass Ladder (South)',
|
||||
'Desert Pass Rocks (North)',
|
||||
'Desert Pass Rocks (South)',
|
||||
'Desert Pass Ladder (North)',
|
||||
'Middle Aged Man',
|
||||
'Octoballoon Water Drop',
|
||||
'Octoballoon Pier',
|
||||
'Skull Woods Rock (East)',
|
||||
'Skull Woods Rock (West)',
|
||||
'Skull Woods Forgotten Bush (West)',
|
||||
'Skull Woods Forgotten Bush (East)',
|
||||
'GT Approach',
|
||||
'GT Leave',
|
||||
'East Dark Death Mountain Bushes',
|
||||
'Bumper Cave Rock (Outer)',
|
||||
'Bumper Cave Rock (Inner)',
|
||||
|
||||
@@ -5,102 +5,86 @@ Helper functions to deliver entrance/exit/region sets to OWG rules.
|
||||
from BaseClasses import Entrance
|
||||
from OWEdges import OWTileRegions
|
||||
|
||||
# Cave regions that superbunny can get through - but only with a sword.
|
||||
sword_required_superbunny_mirror_regions = ["Spiral Cave (Top)"]
|
||||
|
||||
def get_sword_required_superbunny_mirror_regions():
|
||||
"""
|
||||
Cave regions that superbunny can get through - but only with a sword.
|
||||
"""
|
||||
yield 'Spiral Cave (Top)'
|
||||
# Cave regions that superbunny can get through - but only with boots.
|
||||
boots_required_superbunny_mirror_regions = ["Two Brothers House"]
|
||||
|
||||
def get_boots_required_superbunny_mirror_regions():
|
||||
"""
|
||||
Cave regions that superbunny can get through - but only with boots.
|
||||
"""
|
||||
yield 'Two Brothers House'
|
||||
# Cave locations that superbunny can access - but only with boots.
|
||||
boots_required_superbunny_mirror_locations = [
|
||||
"Sahasrahla's Hut - Left",
|
||||
"Sahasrahla's Hut - Middle",
|
||||
"Sahasrahla's Hut - Right",
|
||||
]
|
||||
|
||||
def get_boots_required_superbunny_mirror_locations():
|
||||
"""
|
||||
Cave locations that superbunny can access - but only with boots.
|
||||
"""
|
||||
yield 'Sahasrahla\'s Hut - Left'
|
||||
yield 'Sahasrahla\'s Hut - Middle'
|
||||
yield 'Sahasrahla\'s Hut - Right'
|
||||
# Entrances that can't be superbunny-mirrored into.
|
||||
invalid_mirror_bunny_entrances = [
|
||||
"Hype Cave",
|
||||
"Bonk Fairy (Dark)",
|
||||
"Thieves Town",
|
||||
"Hammer Peg Cave",
|
||||
"Brewery",
|
||||
"Hookshot Cave",
|
||||
"Dark Lake Hylia Ledge Fairy",
|
||||
"Dark Lake Hylia Ledge Spike Cave",
|
||||
"Palace of Darkness",
|
||||
"Misery Mire",
|
||||
"Turtle Rock",
|
||||
"Bonk Rock Cave",
|
||||
"Bonk Fairy (Light)",
|
||||
"50 Rupee Cave",
|
||||
"20 Rupee Cave",
|
||||
"Checkerboard Cave",
|
||||
"Light Hype Fairy",
|
||||
"Waterfall of Wishing",
|
||||
"Light World Bomb Hut",
|
||||
"Mini Moldorm Cave",
|
||||
"Ice Rod Cave",
|
||||
"Sanctuary Grave",
|
||||
"Kings Grave",
|
||||
"Sanctuary Grave",
|
||||
"Hyrule Castle Secret Entrance Drop",
|
||||
"Skull Woods Second Section Hole",
|
||||
"Skull Woods First Section Hole (North)",
|
||||
]
|
||||
|
||||
# Interior locations that can be accessed with superbunny state.
|
||||
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",
|
||||
"Superbunny Cave - Top",
|
||||
"Superbunny Cave - Bottom",
|
||||
"Blind's Hideout - Left",
|
||||
"Blind's Hideout - Right",
|
||||
"Blind's Hideout - Far Left",
|
||||
"Blind's Hideout - Far Right",
|
||||
"Kakariko Well - Left",
|
||||
"Kakariko Well - Middle",
|
||||
"Kakariko Well - Right",
|
||||
"Kakariko Well - Bottom",
|
||||
"Kakariko Tavern",
|
||||
"Library",
|
||||
"Spiral Cave",
|
||||
] + boots_required_superbunny_mirror_locations
|
||||
|
||||
# TODO: Add pottery locations
|
||||
|
||||
|
||||
def get_invalid_mirror_bunny_entrances():
|
||||
"""
|
||||
Entrances that can't be superbunny-mirrored into.
|
||||
"""
|
||||
yield 'Skull Woods Final Section'
|
||||
yield 'Hype Cave'
|
||||
yield 'Bonk Fairy (Dark)'
|
||||
yield 'Thieves Town'
|
||||
yield 'Hammer Peg Cave'
|
||||
yield 'Brewery'
|
||||
yield 'Hookshot Cave'
|
||||
yield 'Dark Lake Hylia Ledge Fairy'
|
||||
yield 'Dark Lake Hylia Ledge Spike Cave'
|
||||
yield 'Palace of Darkness'
|
||||
yield 'Misery Mire'
|
||||
yield 'Turtle Rock'
|
||||
yield 'Bonk Rock Cave'
|
||||
yield 'Bonk Fairy (Light)'
|
||||
yield '50 Rupee Cave'
|
||||
yield '20 Rupee Cave'
|
||||
yield 'Checkerboard Cave'
|
||||
yield 'Light Hype Fairy'
|
||||
yield 'Waterfall of Wishing'
|
||||
yield 'Light World Bomb Hut'
|
||||
yield 'Mini Moldorm Cave'
|
||||
yield 'Ice Rod Cave'
|
||||
yield 'Sanctuary Grave'
|
||||
yield 'Kings Grave'
|
||||
yield 'Sanctuary Grave'
|
||||
yield 'Hyrule Castle Secret Entrance Drop'
|
||||
yield 'Skull Woods Second Section Hole'
|
||||
yield 'Skull Woods First Section Hole (North)'
|
||||
|
||||
|
||||
def get_superbunny_accessible_locations():
|
||||
"""
|
||||
Interior locations that can be accessed with superbunny state.
|
||||
"""
|
||||
|
||||
yield 'Waterfall of Wishing - Left'
|
||||
yield 'Waterfall of Wishing - Right'
|
||||
yield 'King\'s Tomb'
|
||||
yield 'Floodgate'
|
||||
yield 'Floodgate Chest'
|
||||
yield 'Cave 45'
|
||||
yield 'Bonk Rock Cave'
|
||||
yield 'Brewery'
|
||||
yield 'C-Shaped House'
|
||||
yield 'Chest Game'
|
||||
yield 'Mire Shed - Left'
|
||||
yield 'Mire Shed - Right'
|
||||
yield 'Secret Passage'
|
||||
yield 'Ice Rod Cave'
|
||||
yield 'Pyramid Fairy - Left'
|
||||
yield 'Pyramid Fairy - Right'
|
||||
yield 'Superbunny Cave - Top'
|
||||
yield 'Superbunny Cave - Bottom'
|
||||
yield 'Blind\'s Hideout - Left'
|
||||
yield 'Blind\'s Hideout - Right'
|
||||
yield 'Blind\'s Hideout - Far Left'
|
||||
yield 'Blind\'s Hideout - Far Right'
|
||||
yield 'Kakariko Well - Left'
|
||||
yield 'Kakariko Well - Middle'
|
||||
yield 'Kakariko Well - Right'
|
||||
yield 'Kakariko Well - Bottom'
|
||||
yield 'Kakariko Tavern'
|
||||
yield 'Library'
|
||||
yield 'Spiral Cave'
|
||||
for location in get_boots_required_superbunny_mirror_locations():
|
||||
yield location
|
||||
|
||||
|
||||
def get_non_mandatory_exits(world, player):
|
||||
"""
|
||||
Entrances that can be reached with full equipment using overworld glitches and don't need to be an exit.
|
||||
@@ -295,6 +279,7 @@ def overworld_glitches_rules(world, player):
|
||||
#set_owg_rules(player, world, get_glitched_speed_drops_dw(world, player), lambda state: state.can_get_glitched_speed_dw(player))
|
||||
|
||||
# Mirror clip spots.
|
||||
# TODO: Should this also require can_boots_clip
|
||||
set_owg_rules(player, world, get_mirror_clip_spots(world, player), lambda state: state.has_Mirror(player))
|
||||
|
||||
# Mirror offset spots.
|
||||
@@ -319,6 +304,18 @@ def overworld_glitches_rules(world, 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))
|
||||
|
||||
# Bunny pocket
|
||||
if not world.is_tile_swapped(0x00, player):
|
||||
add_alternate_rule(world.get_entrance("Skull Woods Final Section", player), lambda state: state.can_bunny_pocket(player) and state.has("Fire Rod", player))
|
||||
if world.is_tile_swapped(0x05, player):
|
||||
add_alternate_rule(world.get_entrance("DM Hammer Bridge (West)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
||||
add_alternate_rule(world.get_entrance("DM Hammer Bridge (East)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
||||
if not world.is_tile_swapped(0x18, player):
|
||||
add_alternate_rule(world.get_entrance("Bush Yard Pegs (Inner)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
||||
add_alternate_rule(world.get_entrance("Bush Yard Pegs (Outer)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
||||
if world.is_tile_swapped(0x22, player):
|
||||
add_alternate_rule(world.get_entrance("Blacksmith Ledge Peg (West)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
||||
|
||||
|
||||
def add_alternate_rule(entrance, rule):
|
||||
old_rule = entrance.access_rule
|
||||
@@ -335,7 +332,7 @@ def create_no_logic_connections(player, world, connections):
|
||||
parent = world.get_region(parent_region, player)
|
||||
target = world.get_region(target_region, player)
|
||||
connection = Entrance(player, entrance, parent)
|
||||
connection.spot_type = 'Ledge'
|
||||
connection.spot_type = 'OWG'
|
||||
parent.exits.append(connection)
|
||||
connection.connect(target)
|
||||
|
||||
@@ -387,6 +384,8 @@ boots_clips_local = [ # (name, from_region, to_region)
|
||||
|
||||
('Maze Race Item Get Ledge Clip', 'Maze Race Area', 'Maze Race Prize'),
|
||||
|
||||
#('Hobo Water Clip', 'Stone Bridge South Area', 'Stone Bridge Water'), # TODO: Doesn't work with OW Free Terrain
|
||||
|
||||
('Tree Line Water Clip', 'Tree Line Area', 'Tree Line Water'), #requires flippers
|
||||
('Dark Tree Line Water Clip', 'Dark Tree Line Area', 'Dark Tree Line Water'), #requires flippers
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ def link_overworld(world, player):
|
||||
|
||||
categorize_world_regions(world, player)
|
||||
|
||||
if world.logic[player] in ('owglitches', 'nologic'):
|
||||
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
|
||||
create_owg_connections(world, player)
|
||||
|
||||
# crossed shuffle
|
||||
@@ -1486,7 +1486,7 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F
|
||||
elif exit.connected_region.name not in explored_regions \
|
||||
and (exit.connected_region.type == region.type
|
||||
or exit.name in OWExitTypes['OWEdge'] or (cross_world and exit.name in (OWExitTypes['Portal'] + OWExitTypes['Mirror']))) \
|
||||
and (not region_rules or exit.access_rule(blank_state)) and (not ignore_ledges or exit.name not in OWExitTypes['Ledge']):
|
||||
and (not region_rules or exit.access_rule(blank_state)) and (not ignore_ledges or exit.name not in OWExitTypes['Ledge', 'OWG']):
|
||||
explore_region(exit.connected_region.name, exit.connected_region)
|
||||
|
||||
if build_copy_world:
|
||||
|
||||
6
Rom.py
6
Rom.py
@@ -1365,9 +1365,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x180211, gametype) # Game type
|
||||
|
||||
warningflags = 0x00 # none
|
||||
if world.logic[player] in ['owglitches', 'nologic']:
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
warningflags |= 0x20
|
||||
if world.logic[player] in ['minorglitches', 'owglitches', 'nologic']:
|
||||
if world.logic[player] in ['minorglitches', 'owglitches', 'hybridglitches', 'nologic']:
|
||||
warningflags |= 0x40
|
||||
rom.write_byte(0x180212, warningflags) # Warning flags
|
||||
|
||||
@@ -1599,7 +1599,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills
|
||||
rom.write_byte(0x1800A4, 0x01 if world.logic[player] != 'nologic' else 0x00) # enable POD EG fix
|
||||
rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill
|
||||
rom.write_byte(0x180358, 0x01 if (world.logic[player] in ['owglitches', 'nologic']) else 0x00)
|
||||
rom.write_byte(0x180358, 0x01 if (world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']) else 0x00)
|
||||
|
||||
# remove shield from uncle
|
||||
rom.write_bytes(0x6D253, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E])
|
||||
|
||||
72
Rules.py
72
Rules.py
@@ -9,6 +9,7 @@ from Dungeons import dungeon_table
|
||||
from RoomData import DoorKind
|
||||
from OWEdges import OWExitTypes
|
||||
from OverworldGlitchRules import overworld_glitches_rules
|
||||
from UnderworldGlitchRules import underworld_glitches_rules
|
||||
|
||||
|
||||
def set_rules(world, player):
|
||||
@@ -32,7 +33,7 @@ def set_rules(world, player):
|
||||
logging.getLogger('').info('Minor Glitches may be buggy still. No guarantee for proper logic checks.')
|
||||
no_glitches_rules(world, player)
|
||||
fake_flipper_rules(world, player)
|
||||
elif world.logic[player] == 'owglitches':
|
||||
elif world.logic[player] in ['owglitches', 'hybridglitches']:
|
||||
logging.getLogger('').info('There is a chance OWG has bugged edge case rulesets, especially in inverted. Definitely file a report on GitHub if you see anything strange.')
|
||||
# Initially setting no_glitches_rules to set the baseline rules for some
|
||||
# entrances. The overworld_glitches_rules set is primarily additive.
|
||||
@@ -84,6 +85,9 @@ def set_rules(world, player):
|
||||
if not world.is_copied_world:
|
||||
set_bunny_rules(world, player, world.mode[player] == 'inverted')
|
||||
|
||||
# These rules go here because they overwrite/add to some of the above rules
|
||||
if world.logic[player] == 'hybridglitches':
|
||||
underworld_glitches_rules(world, player)
|
||||
|
||||
def mirrorless_path_to_location(world, startName, targetName, player):
|
||||
# If Agahnim is defeated then the courtyard needs to be accessible without using the mirror for the mirror offset glitch.
|
||||
@@ -845,6 +849,9 @@ def global_rules(world, player):
|
||||
set_rule(world.get_entrance('GT Crystal Circles to Ranged Crystal', player), lambda state: state.can_hit_crystal_through_barrier(player) or state.has_blunt_weapon(player) or state.has('Cane of Byrna', player)) # or state.has_beam_sword(player)
|
||||
|
||||
add_key_logic_rules(world, player)
|
||||
|
||||
if world.logic[player] == 'hybridglitches':
|
||||
add_hmg_key_logic_rules(world, player)
|
||||
# End of door rando rules.
|
||||
|
||||
if world.restrict_boss_items[player] != 'none':
|
||||
@@ -1644,6 +1651,8 @@ def find_rules_for_zelda_delivery(world, player):
|
||||
def set_bunny_rules(world, player, inverted):
|
||||
# regions for the exits of multi-entrace caves/drops that bunny cannot pass
|
||||
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
|
||||
all_single_exit_dungeons = ['Eastern Palace', 'Tower of Hera', 'Castle Tower', 'Palace of Darkness', 'Swamp Palace', 'Thieves Town', 'Ice Palace', 'Misery Mire', 'Ganons Tower']
|
||||
hmg_single_exit_dungeons = [d for d in all_single_exit_dungeons if d not in ['Tower of Hera', 'Misery Mire', 'Thieves Town']]
|
||||
bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House',
|
||||
'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)']
|
||||
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree',
|
||||
@@ -1668,6 +1677,9 @@ def set_bunny_rules(world, player, inverted):
|
||||
'Take - Any # 3 Item 1', 'Take - Any # 3 Item 2',
|
||||
'Take - Any # 4 Item 1', 'Take - Any # 4 Item 2',
|
||||
]
|
||||
bunny_pocket_entrances = ['Skull Woods Final Section', 'Bush Yard Pegs (Inner)', 'Bush Yard Pegs (Outer)',
|
||||
'DM Hammer Bridge (West)', 'DM Hammer Bridge (East)', 'Blacksmith Ledge Peg (West)'
|
||||
]
|
||||
|
||||
def path_to_access_rule(path, entrance):
|
||||
return lambda state: state.can_reach(entrance) and all(rule_func(state) for rule_func in path)
|
||||
@@ -1688,12 +1700,31 @@ def set_bunny_rules(world, player, inverted):
|
||||
else:
|
||||
return region.is_light_world
|
||||
|
||||
# Is it possible to do bunny pocket here
|
||||
def can_bunny_pocket_to(world, entrance_name, player):
|
||||
def can_activate_bunny_pocket(region):
|
||||
explored_regions.append(region.name)
|
||||
for ent in region.entrances:
|
||||
if (is_link(ent.parent_region) or
|
||||
(ent.parent_region.type == RegionType.Dungeon and ent.parent_region.name in bunny_revivable_entrances)):
|
||||
return True
|
||||
for ent in region.entrances:
|
||||
if ent.spot_type in ['OWEdge', 'Ledge', 'OpenTerrain'] and ent.parent_region.name not in explored_regions:
|
||||
if can_activate_bunny_pocket(ent.parent_region):
|
||||
return True
|
||||
return False
|
||||
|
||||
entrance = world.get_entrance(entrance_name, player)
|
||||
explored_regions = []
|
||||
return can_activate_bunny_pocket(entrance.parent_region)
|
||||
|
||||
|
||||
def get_rule_to_add(region, location=None, connecting_entrance=None):
|
||||
# In OWG, a location can potentially be superbunny-mirror accessible or
|
||||
# bunny revival accessible.
|
||||
if world.logic[player] == 'owglitches':
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches']:
|
||||
if region.type != RegionType.Dungeon \
|
||||
and (location is None or location.name not in OverworldGlitchRules.get_superbunny_accessible_locations()) \
|
||||
and (location is None or location.name not in OverworldGlitchRules.superbunny_accessible_locations) \
|
||||
and not is_link(region):
|
||||
return lambda state: state.has_Pearl(player)
|
||||
else:
|
||||
@@ -1723,14 +1754,18 @@ def set_bunny_rules(world, player, inverted):
|
||||
new_path = path + [entrance.access_rule]
|
||||
seen_sets.add(frozenset(new_seen))
|
||||
if not is_link(new_region):
|
||||
if world.logic[player] == 'owglitches':
|
||||
if world.logic[player] in ['owglitches', 'hybridglitches']:
|
||||
# Is this a bunny pocketable entrance?
|
||||
if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon:
|
||||
if entrance.name in OverworldGlitchRules.get_invalid_mirror_bunny_entrances():
|
||||
if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances:
|
||||
continue
|
||||
if entrance.name in bunny_pocket_entrances and not can_bunny_pocket_to(world, entrance.name, player):
|
||||
continue
|
||||
if entrance.name in drop_dungeon_entrances:
|
||||
lobby = entrance.connected_region
|
||||
else:
|
||||
lobby = next(exit.connected_region for exit in current.exits if exit.connected_region.type == RegionType.Dungeon)
|
||||
portal_regions = [world.get_region(reg, player) for reg in region.dungeon.regions if reg.endswith('Portal')]
|
||||
lobby = next(reg.connected_region for portal_reg in portal_regions for reg in portal_reg.exits if reg.name.startswith('Enter '))
|
||||
if lobby.name in bunny_revivable_entrances:
|
||||
possible_options.append(path_to_access_rule(new_path, entrance))
|
||||
elif lobby.name in superbunny_revivable_entrances:
|
||||
@@ -1739,21 +1774,23 @@ def set_bunny_rules(world, player, inverted):
|
||||
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance))
|
||||
continue
|
||||
elif region.type == RegionType.Cave and new_region.type != RegionType.Cave:
|
||||
if entrance.name in OverworldGlitchRules.get_invalid_mirror_bunny_entrances():
|
||||
if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances:
|
||||
continue
|
||||
if region.name in OverworldGlitchRules.get_sword_required_superbunny_mirror_regions():
|
||||
if entrance.name in bunny_pocket_entrances and not can_bunny_pocket_to(world, entrance.name, player):
|
||||
continue
|
||||
if region.name in OverworldGlitchRules.sword_required_superbunny_mirror_regions:
|
||||
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance))
|
||||
elif region.name in OverworldGlitchRules.get_boots_required_superbunny_mirror_regions():
|
||||
elif region.name in OverworldGlitchRules.boots_required_superbunny_mirror_regions:
|
||||
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance))
|
||||
elif location and location.name in OverworldGlitchRules.get_superbunny_accessible_locations():
|
||||
if location.name in OverworldGlitchRules.get_boots_required_superbunny_mirror_locations():
|
||||
elif location and location.name in OverworldGlitchRules.superbunny_accessible_locations:
|
||||
if location.name in OverworldGlitchRules.boots_required_superbunny_mirror_locations:
|
||||
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance))
|
||||
elif region.name == 'Kakariko Well (top)':
|
||||
possible_options.append(path_to_access_rule(new_path, entrance))
|
||||
else:
|
||||
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player)], entrance))
|
||||
continue
|
||||
elif region.name == 'Superbunny Cave (Top)' and new_region.name == 'Superbunny Cave (Bottom)' and location and location.name in OverworldGlitchRules.get_superbunny_accessible_locations():
|
||||
elif region.name == 'Superbunny Cave (Top)' and new_region.name == 'Superbunny Cave (Bottom)' and location and location.name in OverworldGlitchRules.superbunny_accessible_locations:
|
||||
possible_options.append(path_to_access_rule(new_path, entrance))
|
||||
else:
|
||||
continue
|
||||
@@ -1767,7 +1804,6 @@ def set_bunny_rules(world, player, inverted):
|
||||
|
||||
# Add requirements for bunny-impassible caves if they occur in the light world
|
||||
for region in [world.get_region(name, player) for name in bunny_impassable_caves]:
|
||||
|
||||
if not is_bunny(region):
|
||||
continue
|
||||
rule = get_rule_to_add(region)
|
||||
@@ -1802,6 +1838,11 @@ def set_bunny_rules(world, player, inverted):
|
||||
continue
|
||||
add_rule(location, get_rule_to_add(region, location))
|
||||
|
||||
for ent_name in bunny_pocket_entrances:
|
||||
bunny_exit = world.get_entrance(ent_name, player)
|
||||
if bunny_exit.connected_region and is_bunny(bunny_exit.parent_region) and not can_bunny_pocket_to(world, ent_name, player):
|
||||
add_rule(bunny_exit, lambda state: state.has_Pearl(player))
|
||||
|
||||
|
||||
drop_dungeon_entrances = {
|
||||
"Sewer Drop",
|
||||
@@ -1929,6 +1970,11 @@ bunny_impassible_if_trapped = {
|
||||
'GT Speed Torch WN', 'Ice Lobby SE'
|
||||
}
|
||||
|
||||
def add_hmg_key_logic_rules(world, player):
|
||||
for toh_loc in world.key_logic[player]['Tower of Hera'].bk_restricted:
|
||||
set_always_allow(world.get_location(toh_loc.name, player), allow_big_key_in_big_chest('Big Key (Tower of Hera)', player))
|
||||
set_always_allow(world.get_location('Swamp Palace - Entrance', player), allow_big_key_in_big_chest('Big Key (Swamp Palace)', player))
|
||||
|
||||
|
||||
def add_key_logic_rules(world, player):
|
||||
key_logic = world.key_logic[player]
|
||||
|
||||
278
UnderworldGlitchRules.py
Normal file
278
UnderworldGlitchRules.py
Normal file
@@ -0,0 +1,278 @@
|
||||
from BaseClasses import Entrance
|
||||
import Rules
|
||||
from OverworldGlitchRules import create_no_logic_connections
|
||||
|
||||
kikiskip_spots = [("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Portal")]
|
||||
|
||||
mireheraswamp_spots = [
|
||||
("Mire to Hera Clip", "Mire Torches Top", "Hera Portal"),
|
||||
("Hera to Swamp Clip", "Mire Torches Top", "Swamp Portal"),
|
||||
]
|
||||
|
||||
icepalace_spots = [("Ice Lobby Clip", "Ice Portal", "Ice Bomb Drop")]
|
||||
|
||||
thievesdesert_spots = [
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert West Portal"),
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert South Portal"),
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert East Portal"),
|
||||
]
|
||||
|
||||
specrock_spots = [("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave (Top)")]
|
||||
|
||||
paradox_spots = [("Paradox Front Teleport", "Paradox Cave Front", "Paradox Cave Chest Area")]
|
||||
|
||||
|
||||
# We need to make connectors at a separate time from the connections, because of how dungeons are linked to regions
|
||||
kikiskip_connectors = [("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Exit")]
|
||||
|
||||
|
||||
mireheraswamp_connectors = [
|
||||
("Mire to Hera Clip", "Mire Torches Top", "Tower of Hera Exit"),
|
||||
("Mire to Hera Clip", "Mire Torches Top", "Swamp Palace Exit"),
|
||||
]
|
||||
|
||||
|
||||
thievesdesert_connectors = [
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (West)"),
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (South)"),
|
||||
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (East)"),
|
||||
]
|
||||
|
||||
specrock_connectors = [
|
||||
("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave Exit (Top)"),
|
||||
("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave Exit"),
|
||||
]
|
||||
|
||||
|
||||
# Create connections between dungeons/locations
|
||||
def create_hybridmajor_connections(world, player):
|
||||
for spots in [
|
||||
kikiskip_spots,
|
||||
mireheraswamp_spots,
|
||||
icepalace_spots,
|
||||
thievesdesert_spots,
|
||||
specrock_spots,
|
||||
paradox_spots,
|
||||
]:
|
||||
create_no_logic_connections(player, world, spots)
|
||||
|
||||
|
||||
# Turn dungeons into connectors
|
||||
def create_hybridmajor_connectors(world, player):
|
||||
for connectors in [
|
||||
kikiskip_connectors,
|
||||
mireheraswamp_connectors,
|
||||
thievesdesert_connectors,
|
||||
specrock_connectors,
|
||||
]:
|
||||
new_connectors = [(connector[0], connector[1], world.get_entrance(connector[2], player).connected_region) for connector in connectors]
|
||||
create_no_logic_connections(player, world, new_connectors)
|
||||
|
||||
|
||||
# For some entrances, we need to fake having pearl, because we're in fake DW/LW.
|
||||
# This creates a copy of the input state that has Moon Pearl.
|
||||
def fake_pearl_state(state, player):
|
||||
if state.has("Moon Pearl", player):
|
||||
return state
|
||||
fake_state = state.copy()
|
||||
fake_state.prog_items["Moon Pearl", player] += 1
|
||||
return fake_state
|
||||
|
||||
|
||||
# Sets the rules on where we can actually go using this clip.
|
||||
# Behavior differs based on what type of ER shuffle we're playing.
|
||||
def dungeon_reentry_rules(world, player, clip: Entrance, dungeon_region: str, dungeon_exit: str):
|
||||
fix_dungeon_exits = world.fix_palaceofdarkness_exit[player]
|
||||
fix_fake_worlds = world.fix_fake_world[player]
|
||||
|
||||
dungeon_entrance = [r for r in world.get_region(dungeon_region, player).entrances if r.name != clip.name][0]
|
||||
if not fix_dungeon_exits: # vanilla, simple, restricted, dungeonssimple; should never have fake worlds fix
|
||||
# Dungeons are only shuffled among themselves. We need to check SW, MM, and AT because they can't be reentered trivially.
|
||||
|
||||
# entrance doesn't exist until you fire rod it from the other side
|
||||
if dungeon_entrance.name == "Skull Woods Final Section":
|
||||
Rules.set_rule(clip, lambda state: False)
|
||||
|
||||
elif dungeon_entrance.name == "Misery Mire":
|
||||
if world.swords[player] == "swordless":
|
||||
Rules.add_rule(clip, lambda state: state.has_misery_mire_medallion(player))
|
||||
else:
|
||||
Rules.add_rule(clip, lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player))
|
||||
|
||||
elif dungeon_entrance.name == "Agahnims Tower":
|
||||
Rules.add_rule(
|
||||
clip,
|
||||
lambda state: state.has("Cape", player)
|
||||
or state.has_beam_sword(player)
|
||||
or state.has("Beat Agahnim 1", player),
|
||||
)
|
||||
|
||||
# Then we set a restriction on exiting the dungeon, so you can't leave unless you got in normally.
|
||||
Rules.add_rule(world.get_entrance(dungeon_exit, player), lambda state: dungeon_entrance.can_reach(state))
|
||||
elif not fix_fake_worlds: # full, dungeonsfull; fixed dungeon exits, but no fake worlds fix
|
||||
# Entry requires the entrance's requirements plus a fake pearl, but you don't gain logical access to the surrounding region.
|
||||
Rules.add_rule(clip, lambda state: dungeon_entrance.access_rule(fake_pearl_state(state, player)))
|
||||
# exiting restriction
|
||||
Rules.add_rule(world.get_entrance(dungeon_exit, player), lambda state: dungeon_entrance.can_reach(state))
|
||||
|
||||
# Otherwise, the shuffle type is lean, lite, crossed, or insanity; all of these do not need additional rules on where we can go,
|
||||
# since the clip links directly to the exterior region.
|
||||
|
||||
|
||||
def underworld_glitches_rules(world, player):
|
||||
# Ice Palace Entrance Clip, needs bombs or cane of somaria to exit bomb drop room
|
||||
Rules.add_rule(
|
||||
world.get_entrance("Ice Bomb Drop SE", player),
|
||||
lambda state: state.can_dash_clip(world.get_region("Ice Lobby", player), player)
|
||||
and (state.can_use_bombs(player) or state.has("Cane of Somaria", player)),
|
||||
combine="or",
|
||||
)
|
||||
|
||||
# Kiki Skip
|
||||
kks = world.get_entrance("Kiki Skip", player)
|
||||
Rules.set_rule(kks, lambda state: state.can_bomb_clip(kks.parent_region, player))
|
||||
dungeon_reentry_rules(world, player, kks, "Palace of Darkness Portal", "Palace of Darkness Exit")
|
||||
|
||||
# Mire -> Hera -> Swamp
|
||||
def mire_clip(state):
|
||||
return state.can_reach("Mire Torches Top", "Region", player) and state.can_dash_clip(
|
||||
world.get_region("Mire Torches Top", player), player
|
||||
)
|
||||
|
||||
def hera_clip(state):
|
||||
return state.can_reach("Hera 4F", "Region", player) and state.can_dash_clip(
|
||||
world.get_region("Hera 4F", player), player
|
||||
)
|
||||
|
||||
Rules.add_rule(
|
||||
world.get_entrance("Hera Startile Corner NW", player),
|
||||
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
|
||||
combine="or",
|
||||
)
|
||||
Rules.add_rule(
|
||||
world.get_location("Tower of Hera - Big Chest", player),
|
||||
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
|
||||
combine="or",
|
||||
)
|
||||
|
||||
mire_to_hera = world.get_entrance("Mire to Hera Clip", player)
|
||||
mire_to_swamp = world.get_entrance("Hera to Swamp Clip", player)
|
||||
Rules.set_rule(mire_to_hera, mire_clip)
|
||||
Rules.set_rule(mire_to_swamp, lambda state: mire_clip(state) and state.has("Flippers", player))
|
||||
|
||||
# Using the entrances for various ER types. Hera -> Swamp never matters because you can only logically traverse with the mire keys
|
||||
dungeon_reentry_rules(world, player, mire_to_hera, "Hera Lobby", "Tower of Hera Exit")
|
||||
dungeon_reentry_rules(world, player, mire_to_swamp, "Swamp Lobby", "Swamp Palace Exit")
|
||||
# We need to set _all_ swamp doors to be openable with mire keys, otherwise the small key can't be behind them - 6 keys because of Pots
|
||||
# Flippers required for all of these doors to prevent locks when flooding
|
||||
for door in [
|
||||
"Swamp Trench 1 Approach ES",
|
||||
"Swamp Hammer Switch SW",
|
||||
"Swamp Entrance Down Stairs",
|
||||
"Swamp Pot Row WS",
|
||||
"Swamp Trench 1 Key Ledge NW",
|
||||
"Swamp Hub WN",
|
||||
"Swamp Hub North Ledge N",
|
||||
"Swamp Crystal Switch EN",
|
||||
"Swamp Push Statue S",
|
||||
"Swamp Waterway NW",
|
||||
"Swamp T SW",
|
||||
]:
|
||||
Rules.add_rule(
|
||||
world.get_entrance(door, player),
|
||||
lambda state: mire_clip(state)
|
||||
and state.has("Small Key (Misery Mire)", player, count=6)
|
||||
and state.has("Flippers", player),
|
||||
combine="or",
|
||||
)
|
||||
# Rules.add_rule(world.get_entrance(door, player), lambda state: mire_clip(state) and state.has('Flippers', player), combine="or")
|
||||
|
||||
Rules.add_rule(
|
||||
world.get_location("Trench 1 Switch", player), lambda state: mire_clip(state) or hera_clip(state), combine="or"
|
||||
)
|
||||
|
||||
# Build the rule for SP moat.
|
||||
# We need to be able to s+q to old man, then go to either Mire or Hera at either Hera or GT.
|
||||
# First we require a certain type of entrance shuffle, then build the rule from its pieces.
|
||||
if not world.swamp_patch_required[player]:
|
||||
if world.shuffle[player] in [
|
||||
"vanilla",
|
||||
"dungeonssimple",
|
||||
"dungeonsfull",
|
||||
"dungeonscrossed",
|
||||
]:
|
||||
rule_map = {
|
||||
"Mire Portal": (lambda state: state.can_reach("Mire Torches Top", "Entrance", player)),
|
||||
"Hera Portal": (lambda state: state.can_reach("Hera Startile Corner NW", "Entrance", player)),
|
||||
}
|
||||
inverted = world.mode[player] == "inverted"
|
||||
|
||||
def hera_rule(state):
|
||||
return (state.has("Moon Pearl", player) or not inverted) and rule_map.get(
|
||||
world.get_entrance("Tower of Hera", player).connected_region.name, lambda state: False
|
||||
)(state)
|
||||
|
||||
def gt_rule(state):
|
||||
return (state.has("Moon Pearl", player) or inverted) and rule_map.get(
|
||||
world.get_entrance(("Ganons Tower"), player).connected_region.name, lambda state: False
|
||||
)(state)
|
||||
|
||||
def mirrorless_moat_rule(state):
|
||||
return (
|
||||
state.can_reach("Old Man S&Q", "Entrance", player)
|
||||
and state.has("Flippers", player)
|
||||
and mire_clip(state)
|
||||
and (hera_rule(state) or gt_rule(state))
|
||||
)
|
||||
|
||||
Rules.add_rule(
|
||||
world.get_entrance("Swamp Lobby Moat", player), lambda state: mirrorless_moat_rule(state), combine="or"
|
||||
)
|
||||
|
||||
# Thieves -> Desert
|
||||
Rules.add_rule(
|
||||
world.get_entrance("Thieves to Desert Clip", player),
|
||||
lambda state: state.can_dash_clip(world.get_region("Thieves Attic", player), player),
|
||||
)
|
||||
dungeon_reentry_rules(
|
||||
world,
|
||||
player,
|
||||
world.get_entrance("Thieves to Desert Clip", player),
|
||||
"Desert West Portal",
|
||||
"Desert Palace Exit (West)",
|
||||
)
|
||||
dungeon_reentry_rules(
|
||||
world,
|
||||
player,
|
||||
world.get_entrance("Thieves to Desert Clip", player),
|
||||
"Desert South Portal",
|
||||
"Desert Palace Exit (South)",
|
||||
)
|
||||
dungeon_reentry_rules(
|
||||
world,
|
||||
player,
|
||||
world.get_entrance("Thieves to Desert Clip", player),
|
||||
"Desert East Portal",
|
||||
"Desert Palace Exit (East)",
|
||||
)
|
||||
|
||||
# Collecting left chests in Paradox Cave using a dash clip -> dash citrus, 1f right, teleport up
|
||||
paradox_left_chests = ["Paradox Cave Lower - Far Left", "Paradox Cave Lower - Left", "Paradox Cave Lower - Middle"]
|
||||
for location in paradox_left_chests:
|
||||
Rules.add_rule(
|
||||
world.get_location(location, player),
|
||||
lambda state: state.can_dash_clip(world.get_location(location, player).parent_region, player),
|
||||
"or",
|
||||
)
|
||||
|
||||
# Collecting right chests in Paradox Cave using a dash clip on left side -> dash citrus, 1f right, teleport up, then hitting the switch
|
||||
paradox_right_chests = ["Paradox Cave Lower - Right", "Paradox Cave Lower - Far Right"]
|
||||
for location in paradox_right_chests:
|
||||
Rules.add_rule(
|
||||
world.get_location(location, player),
|
||||
lambda state: (
|
||||
state.can_dash_clip(world.get_location(location, player).parent_region, player)
|
||||
and state.can_hit_crystal(player)
|
||||
),
|
||||
"or",
|
||||
)
|
||||
@@ -23,6 +23,7 @@
|
||||
"noglitches",
|
||||
"minorglitches",
|
||||
"owglitches",
|
||||
"hybridglitches",
|
||||
"nologic"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
"building.collection.spheres": "Building up collection spheres",
|
||||
"building.calculating.spheres": "Calculated sphere %i, containing %i of %i progress items.",
|
||||
"building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items.",
|
||||
"old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s"
|
||||
"old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s",
|
||||
"hybridglitches.door.shuffle": "Hybrid Major Glitches is not currently compatible with Door Shuffle."
|
||||
},
|
||||
"help": {
|
||||
"lang": [ "App Language, if available, defaults to English" ],
|
||||
@@ -64,11 +65,13 @@
|
||||
"bps": [ "Output BPS patches instead of ROMs"],
|
||||
"logic": [
|
||||
"Select Enforcement of Item Requirements. (default: %(default)s)",
|
||||
"No Glitches: No Glitch knowledge required.",
|
||||
"Minor Glitches: May require Fake Flippers, Bunny Revival",
|
||||
" and Dark Room Navigation.",
|
||||
"No Logic: Distribute items without regard for",
|
||||
" item requirements."
|
||||
"No Glitches: No Glitch knowledge required.",
|
||||
"Minor Glitches: May require Fake Flippers, Bunny Revival",
|
||||
" and Dark Room Navigation.",
|
||||
"Overworld Glitches: May require overworld clips and teleports.",
|
||||
"Hybrid Major Glitches: May require underworld clips.",
|
||||
"No Logic: Distribute items without regard for",
|
||||
" item requirements."
|
||||
],
|
||||
"mode": [
|
||||
"Select game mode. (default: %(default)s)",
|
||||
|
||||
@@ -263,6 +263,7 @@
|
||||
"randomizer.item.logiclevel.noglitches": "No Glitches",
|
||||
"randomizer.item.logiclevel.minorglitches": "Minor Glitches",
|
||||
"randomizer.item.logiclevel.owglitches": "Overworld Glitches",
|
||||
"randomizer.item.logiclevel.hybridglitches": "Hybrid Major Glitches",
|
||||
"randomizer.item.logiclevel.nologic": "No Logic",
|
||||
|
||||
"randomizer.item.goal": "Goal",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"noglitches",
|
||||
"minorglitches",
|
||||
"owglitches",
|
||||
"hybridglitches",
|
||||
"nologic"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1317,7 +1317,7 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit):
|
||||
invalid_connections = Must_Exit_Invalid_Connections.copy()
|
||||
invalid_cave_connections = defaultdict(set)
|
||||
|
||||
if avail.world.logic[avail.player] in ['owglitches', 'nologic']:
|
||||
if avail.world.logic[avail.player] in ['owglitches', 'hybridglitches', 'nologic']:
|
||||
import OverworldGlitchRules
|
||||
for entrance in OverworldGlitchRules.get_non_mandatory_exits(avail.world, avail.player):
|
||||
invalid_connections[entrance] = set()
|
||||
|
||||
@@ -46,8 +46,9 @@ def roll_settings(weights):
|
||||
|
||||
ret.algorithm = get_choice('algorithm')
|
||||
|
||||
glitch_map = {'none': 'noglitches', 'no_logic': 'nologic', 'owglitches': 'owglitches',
|
||||
'owg': 'owglitches', 'minorglitches': 'minorglitches'}
|
||||
glitch_map = {'none': 'noglitches', 'minorglitches': 'minorglitches', 'no_logic': 'nologic',
|
||||
'hmg': 'hybridglitches', 'hybridglitches': 'hybridglitches',
|
||||
'owg': 'owglitches', 'owglitches': 'owglitches'}
|
||||
glitches_required = get_choice('glitches_required')
|
||||
if glitches_required is not None:
|
||||
if glitches_required not in glitch_map.keys():
|
||||
|
||||
35
test/customizer/hmg/fireless_ice.yaml
Normal file
35
test/customizer/hmg/fireless_ice.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: vanilla
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
placements:
|
||||
1:
|
||||
Ice Palace - Compass Chest: Fire Rod
|
||||
Ice Palace - Freezor Chest: Bombos
|
||||
42
test/customizer/hmg/hammer_in_swamp.yaml
Normal file
42
test/customizer/hmg/hammer_in_swamp.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: vanilla
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Lamp
|
||||
- Tempered Sword
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
placements:
|
||||
1:
|
||||
Swamp Palace - Big Chest: Hammer
|
||||
34
test/customizer/hmg/mearl_in_pod.yaml
Normal file
34
test/customizer/hmg/mearl_in_pod.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: vanilla
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
placements:
|
||||
1:
|
||||
Palace of Darkness - Shooter Room: Moon Pearl
|
||||
42
test/customizer/hmg/mirrorless_swamp.yaml
Normal file
42
test/customizer/hmg/mirrorless_swamp.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: vanilla
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Lamp
|
||||
- Tempered Sword
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
placements:
|
||||
1:
|
||||
Swamp Palace - Big Chest: Magic Mirror
|
||||
44
test/customizer/hmg/pod_as_connector.yaml
Normal file
44
test/customizer/hmg/pod_as_connector.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: crossed
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
entrances:
|
||||
1:
|
||||
entrances:
|
||||
Dark Lake Hylia Ledge Hint: Dark World Hammer Peg Cave
|
||||
exits:
|
||||
Links House: Chris Houlihan Room Exit
|
||||
two-way:
|
||||
Dark Lake Hylia Ledge Fairy: Palace of Darkness Exit
|
||||
Lake Hylia Fortune Teller: Spectacle Rock Cave Exit
|
||||
Links House: Links House Exit
|
||||
placements:
|
||||
1:
|
||||
Peg Cave: Moon Pearl
|
||||
55
test/customizer/hmg/swamp_as_connector.yaml
Normal file
55
test/customizer/hmg/swamp_as_connector.yaml
Normal file
@@ -0,0 +1,55 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: crossed
|
||||
start_inventory:
|
||||
1:
|
||||
- Hookshot
|
||||
- Lamp
|
||||
- Hammer
|
||||
- Magic Mirror
|
||||
- Tempered Sword
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
entrances:
|
||||
1:
|
||||
entrances:
|
||||
Dark Lake Hylia Ledge Hint: Dark World Hammer Peg Cave
|
||||
exits:
|
||||
Links House: Chris Houlihan Room Exit
|
||||
two-way:
|
||||
Dark Lake Hylia Ledge Fairy: Swamp Palace Exit
|
||||
Lake Hylia Fortune Teller: Misery Mire Exit
|
||||
Links House: Links House Exit
|
||||
placements:
|
||||
1:
|
||||
Peg Cave: Moon Pearl
|
||||
|
||||
44
test/customizer/hmg/swamp_small_in_swamp_back.yaml
Normal file
44
test/customizer/hmg/swamp_small_in_swamp_back.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
accessibility: items
|
||||
door_shuffle: vanilla
|
||||
logic: hybridglitches
|
||||
mode: open
|
||||
shuffle: vanilla
|
||||
start_inventory:
|
||||
1:
|
||||
- Hookshot
|
||||
- Lamp
|
||||
- Hammer
|
||||
- Magic Mirror
|
||||
- Tempered Sword
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
- Boss Heart Container
|
||||
doors:
|
||||
1:
|
||||
doors:
|
||||
Hera Beetles WS: Hera Startile Corner ES
|
||||
Hera Startile Corner ES: Hera Beetles WS
|
||||
Hera Startile Corner NW: Hera Startile Wide SW
|
||||
Hera Startile Wide SW: Hera Startile Corner NW
|
||||
Skull 1 Lobby ES: Skull Map Room WS
|
||||
Skull 2 West Lobby ES: Skull Small Hall WS
|
||||
Skull 2 West Lobby NW: Skull X Room SW
|
||||
Skull Big Chest N: Skull Pull Switch S
|
||||
Skull Compass Room WS: Skull Left Drop ES
|
||||
Skull Final Drop WS: Skull Spike Corner ES
|
||||
Skull Left Drop ES: Skull Compass Room WS
|
||||
Skull Map Room WS: Skull 1 Lobby ES
|
||||
Skull Pot Circle WN: Skull Pull Switch EN
|
||||
Skull Pull Switch EN: Skull Pot Circle WN
|
||||
Skull Pull Switch S: Skull Big Chest N
|
||||
Skull Small Hall WS: Skull 2 West Lobby ES
|
||||
Skull Spike Corner ES: Skull Final Drop WS
|
||||
Skull X Room SW: Skull 2 West Lobby NW
|
||||
lobbies: {}
|
||||
# placements:
|
||||
# 1:
|
||||
# Swamp Palace - Entrance: Boss Heart Container
|
||||
34
test/suite/hmg/entrance_bunny_pocket_sw.yaml
Normal file
34
test/suite/hmg/entrance_bunny_pocket_sw.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
meta:
|
||||
players: 1
|
||||
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
shuffle: crossed
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Pegasus Boots
|
||||
- Progressive Sword
|
||||
- Hammer
|
||||
- Progressive Glove
|
||||
- Progressive Glove
|
||||
- Fire Rod
|
||||
- Book of Mudora
|
||||
- Bottle
|
||||
- Magic Mirror
|
||||
- Lamp
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Moon Pearl
|
||||
locations:
|
||||
Pyramid Fairy - Left: True
|
||||
entrances:
|
||||
1:
|
||||
entrances:
|
||||
Skull Woods Final Section: Pyramid Fairy
|
||||
two-way:
|
||||
Chicken House: Two Brothers House Exit (West)
|
||||
Skull Woods Second Section Door (West): Two Brothers House Exit (East)
|
||||
|
||||
17
test/suite/hmg/fireless_ice.yaml
Normal file
17
test/suite/hmg/fireless_ice.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Moon Pearl
|
||||
- Progressive Sword
|
||||
- Hammer
|
||||
- Progressive Glove
|
||||
- Progressive Glove
|
||||
placements:
|
||||
1:
|
||||
Ice Palace - Map Chest: Bombos
|
||||
Ice Palace - Iced T Room: Fire Rod
|
||||
20
test/suite/hmg/flippers_locked_flippers.yaml
Normal file
20
test/suite/hmg/flippers_locked_flippers.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Pegasus Boots
|
||||
- Moon Pearl
|
||||
- Progressive Sword
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Flippers
|
||||
locations:
|
||||
Zora's Ledge: True
|
||||
Hobo: True
|
||||
Ice Palace - Boss: True
|
||||
Swamp Palace - Entrance: False
|
||||
|
||||
29
test/suite/hmg/flippers_wraps.yaml
Normal file
29
test/suite/hmg/flippers_wraps.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: owglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Pegasus Boots
|
||||
- Moon Pearl
|
||||
- Progressive Sword
|
||||
- Flippers
|
||||
placements:
|
||||
1:
|
||||
Peg Cave: Magic Mirror
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Hammer
|
||||
locations:
|
||||
Link's House: True
|
||||
Magic Bat: False
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Progressive Glove
|
||||
locations:
|
||||
Link's House: True
|
||||
Ice Palace - Freezor Chest: False
|
||||
|
||||
26
test/suite/hmg/hera_from_mire.yaml
Normal file
26
test/suite/hmg/hera_from_mire.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Moon Pearl
|
||||
- Progressive Sword
|
||||
- Lamp
|
||||
- Magic Mirror
|
||||
- Ether
|
||||
- Quake
|
||||
- Bombos
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Big Key (Tower of Hera)
|
||||
locations:
|
||||
Tower of Hera - Big Key Chest: True
|
||||
Tower of Hera - Basement Cage: True
|
||||
Tower of Hera - Map Chest: True
|
||||
Tower of Hera - Compass Chest: True
|
||||
Tower of Hera - Big Chest: True
|
||||
Tower of Hera - Boss: True
|
||||
26
test/suite/hmg/inverted_inaccessible_desert.yaml
Normal file
26
test/suite/hmg/inverted_inaccessible_desert.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
mode: inverted
|
||||
shuffle: crossed
|
||||
|
||||
start_inventory:
|
||||
1:
|
||||
- Pegasus Boots
|
||||
- Progressive Sword
|
||||
- Hammer
|
||||
- Fire Rod
|
||||
placements:
|
||||
1:
|
||||
Desert Palace - Boss: Moon Pearl
|
||||
entrances:
|
||||
1:
|
||||
two-way:
|
||||
Skull Woods Final Section: Desert Palace Exit (West)
|
||||
Skull Woods Second Section Door (West): Desert Palace Exit (East)
|
||||
Thieves Town: Thieves Town Exit
|
||||
Hyrule Castle Entrance (East): Desert Palace Exit (South)
|
||||
Hyrule Castle Entrance (West): Desert Palace Exit (North)
|
||||
|
||||
31
test/suite/hmg/inverted_moon_pearl_locs.yaml
Normal file
31
test/suite/hmg/inverted_moon_pearl_locs.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
mode: inverted
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Progressive Sword
|
||||
- Progressive Sword
|
||||
- Book of Mudora
|
||||
- Lamp
|
||||
- Magic Mirror
|
||||
- Ether
|
||||
- Quake
|
||||
- Bombos
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Moon Pearl
|
||||
locations:
|
||||
Tower of Hera - Big Chest: True
|
||||
Desert Palace - Big Chest: True
|
||||
Eastern Palace - Big Chest: True
|
||||
Bombos Tablet: True
|
||||
Cave 45: True
|
||||
|
||||
|
||||
|
||||
|
||||
48
test/suite/hmg/moon_pearl_locs.yaml
Normal file
48
test/suite/hmg/moon_pearl_locs.yaml
Normal file
@@ -0,0 +1,48 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Pegasus Boots
|
||||
- Flippers
|
||||
- Fire Rod
|
||||
- Book of Mudora
|
||||
- Progressive Sword
|
||||
- Progressive Sword
|
||||
- Lamp
|
||||
- Magic Mirror
|
||||
- Ether
|
||||
- Quake
|
||||
- Bombos
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Moon Pearl
|
||||
locations:
|
||||
Skull Woods - Compass Chest: True
|
||||
Skull Woods - Bridge Room: True
|
||||
Palace of Darkness - Shooter Room: True
|
||||
Palace of Darkness - The Arena - Bridge: True
|
||||
Palace of Darkness - Stalfos Basement: True
|
||||
Palace of Darkness - Big Key Chest: True
|
||||
Palace of Darkness - The Arena - Ledge: True
|
||||
Palace of Darkness - Map Chest: True
|
||||
Palace of Darkness - Compass Chest: True
|
||||
Palace of Darkness - Dark Basement - Left: True
|
||||
Palace of Darkness - Dark Basement - Right: True
|
||||
Palace of Darkness - Dark Maze - Top: True
|
||||
Palace of Darkness - Dark Maze - Bottom: True
|
||||
Palace of Darkness - Big Chest: True
|
||||
Palace of Darkness - Harmless Hellway: True
|
||||
Palace of Darkness - Boss: True
|
||||
Bombos Tablet: True
|
||||
C-Shaped House: True
|
||||
Pyramid Fairy - Left: True
|
||||
Swamp Palace - Entrance: False
|
||||
Thieves' Town - Map Chest: False
|
||||
|
||||
|
||||
|
||||
|
||||
25
test/suite/hmg/pearlless_sw.yaml
Normal file
25
test/suite/hmg/pearlless_sw.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
meta:
|
||||
players: 1
|
||||
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Pegasus Boots
|
||||
- Progressive Sword
|
||||
- Hammer
|
||||
- Progressive Glove
|
||||
- Progressive Glove
|
||||
- Fire Rod
|
||||
- Book of Mudora
|
||||
- Bottle
|
||||
- Magic Mirror
|
||||
- Lamp
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Moon Pearl
|
||||
locations:
|
||||
Skull Woods - Bridge Room: True
|
||||
43
test/suite/hmg/swamp_from_mire.yaml
Normal file
43
test/suite/hmg/swamp_from_mire.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
meta:
|
||||
players: 1
|
||||
settings:
|
||||
1:
|
||||
logic: hybridglitches
|
||||
start_inventory:
|
||||
1:
|
||||
- Flippers
|
||||
- Moon Pearl
|
||||
- Progressive Sword
|
||||
- Lamp
|
||||
- Magic Mirror
|
||||
- Ether
|
||||
- Quake
|
||||
- Bombos
|
||||
advanced_placements:
|
||||
1:
|
||||
- type: Verification
|
||||
item: Small Key (Swamp Palace)
|
||||
locations:
|
||||
Swamp Palace - Entrance: True
|
||||
Swamp Palace - Map Chest: True
|
||||
Swamp Palace - Big Chest: True
|
||||
Swamp Palace - Compass Chest: True
|
||||
Swamp Palace - West Chest: True
|
||||
Swamp Palace - Big Key Chest: True
|
||||
Swamp Palace - Flooded Room - Left: True
|
||||
Swamp Palace - Flooded Room - Right: True
|
||||
Swamp Palace - Waterfall Room: True
|
||||
Swamp Palace - Boss: True
|
||||
- type: Verification
|
||||
item: Big Key (Swamp Palace)
|
||||
locations:
|
||||
Swamp Palace - Entrance: True
|
||||
Swamp Palace - Map Chest: True
|
||||
Swamp Palace - Big Chest: True
|
||||
Swamp Palace - Compass Chest: True
|
||||
Swamp Palace - West Chest: True
|
||||
Swamp Palace - Big Key Chest: True
|
||||
Swamp Palace - Flooded Room - Left: True
|
||||
Swamp Palace - Flooded Room - Right: True
|
||||
Swamp Palace - Waterfall Room: True
|
||||
Swamp Palace - Boss: True
|
||||
Reference in New Issue
Block a user