Fix up minor bugs in existing algorithms. Renamed Simple to Restricted. Added new Simple algorithm that shuffles caves in pairs and only mixes up things on light world death mountain. Added madness shuffle algorithm that mixes up entrances and exits independently from each other. This about as wild as we can get right now without modifying the game logic. Only Ganon's Tower, Ganon and Link's House remain fixed for gameplay reasons.

This commit is contained in:
LLCoolDave 2017-05-21 16:05:55 +02:00
parent 329cdeebdb
commit c253fbf746
1 changed files with 364 additions and 10 deletions

View File

@ -55,6 +55,83 @@ def link_entrances(world):
ret.append(simple_shuffle_dungeons(world)) ret.append(simple_shuffle_dungeons(world))
old_man_entrances = list(Old_Man_Entrances)
caves = list(Cave_Exits)
three_exit_caves = list(Cave_Three_Exits)
single_doors = list(Single_Cave_Doors)
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors)
door_targets = list(Single_Cave_Targets)
# we shuffle all 2 entrance caves as pairs as a start
# start with the ones that need to be directed
two_door_caves = list(Two_Door_Caves_Directional)
random.shuffle(two_door_caves)
random.shuffle(caves)
while two_door_caves:
entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop()
ret.append(connect_two_way(world, entrance1, exit1))
ret.append(connect_two_way(world, entrance2, exit2))
# now the remaining pairs
two_door_caves = list(Two_Door_Caves)
random.shuffle(two_door_caves)
while two_door_caves:
entrance1, entrance2 = two_door_caves.pop()
exit1, exit2 = caves.pop()
ret.append(connect_two_way(world, entrance1, exit1))
ret.append(connect_two_way(world, entrance2, exit2))
# at this point only Light World death mountain entrances remain
# place old man, has limited options
remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Death Mountain Climb (Bottom)', 'Death Mountain Climb (Middle)', 'Death Mountain Climb (Top)',
'Death Mountain Fairy Drop Cave (Bottom)', 'Death Mountain Fairy Drop Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)']
random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop()
remaining_entrances.extend(old_man_entrances)
random.shuffle(remaining_entrances)
old_man_entrance = remaining_entrances.pop()
ret.append(connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)'))
ret.append(connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)'))
# add old man house to ensure it is alwayxs somewhere on light death mountain
caves.append(('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)'))
caves.extend(list(three_exit_caves))
# connect rest
ret.append(connect_caves(world, remaining_entrances, [], caves))
# scramble holes
ret.append(scramble_holes(world))
# place blacksmith, has limited options
random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop()
ret.append(connect_one_way(world, blacksmith_hut, 'Blacksmiths Hut'))
bomb_shop_doors.extend(blacksmith_doors)
# place dam and pyramid fairy, have limited options
# ToDo Dam might be behind fat fairy if we later check for this when placing crystal 5 and 6
random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop()
ret.append(connect_one_way(world, bomb_shop, 'Big Bomb Shop'))
dam = bomb_shop_doors.pop()
ret.append(connect_one_way(world, dam, 'Dam'))
single_doors.extend(bomb_shop_doors)
# tavern back door cannot be shuffled yet
ret.append(connect_doors(world, ['Tavern North'], ['Tavern']))
# place remaining doors
ret.append(connect_doors(world, single_doors, door_targets))
elif world.shuffle == 'restricted':
ret.append('Mixed Entrances:\n\n')
ret.append(simple_shuffle_dungeons(world))
lw_entrances = list(LW_Entrances) lw_entrances = list(LW_Entrances)
dw_entrances = list(DW_Entrances) dw_entrances = list(DW_Entrances)
dw_must_exits = list(DW_Entrances_Must_Exit) dw_must_exits = list(DW_Entrances_Must_Exit)
@ -72,9 +149,14 @@ def link_entrances(world):
caves.extend(three_exit_caves) caves.extend(three_exit_caves)
# place old man, has limited options # place old man, has limited options
ret.append(connect_caves(world, old_man_entrances, [], [('Old Man Cave Exit (West)', 'Old Man Cave Exit (East)')])) # exit has to come from specific set of doors, the entrance is free to move about
# merge with remainder of lw entrances random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop()
lw_entrances.extend(old_man_entrances) lw_entrances.extend(old_man_entrances)
random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop()
ret.append(connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)'))
ret.append(connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)'))
# place Old Man House in Light World, so using the s&q point does not cause fake dark world # place Old Man House in Light World, so using the s&q point does not cause fake dark world
ret.append(connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')])) ret.append(connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')]))
@ -129,17 +211,27 @@ def link_entrances(world):
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
lw_entrances.append('Hyrule Castle Entrance (South)') lw_entrances.append('Hyrule Castle Entrance (South)')
ret.append(connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits)) # we randomize which world requirements we fulfill first so we get better dungeon distribution
ret.append(connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits)) if random.randint(0, 1) == 0:
ret.append(connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits))
ret.append(connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits))
else:
ret.append(connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits))
ret.append(connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits))
if world.mode == 'standard': if world.mode == 'standard':
# rest of hyrule castle must be in light world to avoid fake darkworld stuff # rest of hyrule castle must be in light world to avoid fake darkworld stuff
ret.append(connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')])) ret.append(connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')]))
ret.append(connect_caves(world, lw_entrances, [], list(LW_Dungeon_Exits))) # Aghanim must be light world ret.append(connect_caves(world, lw_entrances, [], list(LW_Dungeon_Exits))) # Aghanim must be light world
# place old man, has limited options # place old man, has limited options
ret.append(connect_caves(world, old_man_entrances, [], [('Old Man Cave Exit (West)', 'Old Man Cave Exit (East)')])) # exit has to come from specific set of doors, the entrance is free to move about
# merge with remainder of lw entrances random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop()
lw_entrances.extend(old_man_entrances) lw_entrances.extend(old_man_entrances)
random.shuffle(lw_entrances)
old_man_entrance = lw_entrances.pop()
ret.append(connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)'))
ret.append(connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)'))
# place Old Man House in Light World, so using the s&q point does not cause fake dark world # place Old Man House in Light World, so using the s&q point does not cause fake dark world
ret.append(connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')])) ret.append(connect_caves(world, lw_entrances, [], [('Old Man House Exit (Bottom)', 'Old Man House Exit (Top)')]))
@ -171,6 +263,239 @@ def link_entrances(world):
# place remaining doors # place remaining doors
ret.append(connect_doors(world, single_doors, door_targets)) ret.append(connect_doors(world, single_doors, door_targets))
elif world.shuffle == 'madness':
# here lie dragons, connections are no longer two way
ret.append('Mixed Entrances:\n\n')
lw_entrances = list(LW_Entrances + LW_Dungeon_Entrances)
dw_entrances = list(DW_Entrances + DW_Dungeon_Entrances)
dw_entrances_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit)
lw_doors = list(LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit) + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Thieves Forest Hideout Stump',
'Lumberjack Tree Cave', 'Hyrule Castle Secret Entrance Stairs'] + list(Old_Man_Entrances)
dw_doors = list(DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)']
random.shuffle(lw_doors)
random.shuffle(dw_doors)
dw_entrances_must_exits.append('Skull Woods Second Section Door (West)')
dw_entrances.append('Skull Woods Second Section Door (East)')
dw_entrances.append('Skull Woods First Section Door')
lw_entrances.extend(['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Thieves Forest Hideout Stump', 'Lumberjack Tree Cave', 'Hyrule Castle Entrance (South)'])
lw_entrances_must_exits = list(LW_Dungeon_Entrances_Must_Exit)
old_man_entrances = list(Old_Man_Entrances)
mandatory_light_world = ['Aghanims Tower Exit', 'Old Man House Exit (Bottom)', 'Old Man House Exit (Top)']
mandatory_dark_world = []
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits)
# shuffle up holes
lw_hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Thieves Forest Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave']
dw_hole_entrances = ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
hole_targets = [('Kakariko Well Exit', 'Kakariko Well (top)'),
('Bat Cave Exit', 'Bat Cave (right)'),
('North Fairy Cave Exit', 'North Fairy Cave'),
('Thieves Forest Hideout Exit', 'Thieves Forest Hideout (top)'),
('Lumberjack Tree Exit', 'Lumberjack Tree (top)'),
(('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Woods Second Section')]
if world.mode == 'standard':
# cannot move uncle cave
ret.append(connect_one_way(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'))
ret.append(connect_exit(world, 'Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Stairs'))
ret.append(connect_entrance(world, lw_doors.pop(), 'Hyrule Castle Secret Entrance Exit'))
else:
lw_hole_entrances.append('Hyrule Castle Secret Entrance Drop')
hole_targets.append(('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance'))
lw_entrances.append('Hyrule Castle Secret Entrance Stairs')
random.shuffle(lw_hole_entrances)
random.shuffle(dw_hole_entrances)
random.shuffle(hole_targets)
# decide if skull woods first section should be in light or dark world
sw_light = random.randint(0, 1) == 0
if sw_light:
sw_hole_pool = lw_hole_entrances
mandatory_light_world.append('Skull Woods First Section Exit')
else:
sw_hole_pool = dw_hole_entrances
mandatory_dark_world.append('Skull Woods First Section Exit')
for target in ['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']:
ret.append(connect_one_way(world, sw_hole_pool.pop(), target))
# sanctuary has to be in light world
ret.append(connect_one_way(world, lw_hole_entrances.pop(), 'Sewer Drop'))
mandatory_light_world.append('Sanctuary Exit')
# fill up remaining holes
for hole in dw_hole_entrances:
exits, target = hole_targets.pop()
mandatory_dark_world.append(exits)
ret.append(connect_one_way(world, hole, target))
for hole in lw_hole_entrances:
exits, target = hole_targets.pop()
mandatory_light_world.append(exits)
ret.append(connect_one_way(world, hole, target))
# hyrule castle handling
if world.mode == 'standard':
# must connect front of hyrule castle to do escape
ret.append(connect_entrance(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)'))
random.shuffle(lw_entrances)
ret.append(connect_exit(world, 'Hyrule Castle Exit (South)', lw_entrances.pop()))
mandatory_light_world.append(('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
else:
lw_doors.append('Hyrule Castle Entrance (South)')
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
# now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist):
random.shuffle(cavelist)
candidate = None
for cave in cavelist:
if isinstance(cave, tuple) and len(cave) > 1:
# special handling: TRock has two entries that we should consider entrance only
if cave[0] == 'Turtle Rock Exit (Front)' and len(cave) == 2:
continue
candidate = cave
break
if candidate is None:
raise RuntimeError('No suitable cave.')
cavelist.remove(candidate)
return candidate
def connect_reachable_exit(entrance, general, worldspecific, worldoors):
# select which one is the primary option
if random.randint(0, 1) == 0:
primary = general
secondary = worldspecific
else:
primary = worldspecific
secondary = general
try:
cave = extract_reachable_exit(primary)
except RuntimeError:
cave = extract_reachable_exit(secondary)
exit = cave[-1]
cave = cave[:-1]
ret.append(connect_exit(world, exit, entrance))
ret.append(connect_entrance(world, worldoors.pop(), exit))
# rest of cave now is forced to be in this world
worldspecific.append(cave)
# we randomize which world requirements we fulfill first so we get better dungeon distribution
if random.randint(0, 1) == 0:
for entrance in lw_entrances_must_exits:
connect_reachable_exit(entrance, caves, mandatory_light_world, lw_doors)
for entrance in dw_entrances_must_exits:
connect_reachable_exit(entrance, caves, mandatory_dark_world, dw_doors)
else:
for entrance in dw_entrances_must_exits:
connect_reachable_exit(entrance, caves, mandatory_dark_world, dw_doors)
for entrance in lw_entrances_must_exits:
connect_reachable_exit(entrance, caves, mandatory_light_world, lw_doors)
# place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about
random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop()
lw_entrances.extend(old_man_entrances)
random.shuffle(lw_entrances)
ret.append(connect_exit(world, 'Old Man Cave Exit (East)', old_man_exit))
ret.append(connect_entrance(world, lw_doors.pop(), 'Old Man Cave Exit (East)'))
mandatory_light_world.append('Old Man Cave Exit (West)')
# we connect up the mandatory associations we have found
for mandatory in mandatory_light_world:
if not isinstance(mandatory, tuple):
mandatory = (mandatory,)
for exit in mandatory:
# point out somewhere
ret.append(connect_exit(world, exit, lw_entrances.pop()))
# point in from somewhere
ret.append(connect_entrance(world, lw_doors.pop(), exit))
for mandatory in mandatory_dark_world:
if not isinstance(mandatory, tuple):
mandatory = (mandatory,)
for exit in mandatory:
# point out somewhere
ret.append(connect_exit(world, exit, dw_entrances.pop()))
# point in from somewhere
ret.append(connect_entrance(world, dw_doors.pop(), exit))
# handle remaining caves
while caves:
# connect highest exit count caves first, prevent issue where we have 2 or 3 exits accross worlds left to fill
cave_candidate = (None, 0)
for i, cave in enumerate(caves):
if isinstance(cave, str):
cave = (cave,)
if len(cave) > cave_candidate[1]:
cave_candidate = (i, len(cave))
cave = caves.pop(cave_candidate[0])
place_lightworld = random.randint(0, 1) == 0
if place_lightworld:
target_doors = lw_doors
target_entrances = lw_entrances
else:
target_doors = dw_doors
target_entrances = dw_entrances
if isinstance(cave, str):
cave = (cave,)
# check if we can still fit the cave into our target group
if len(target_doors) < len(cave):
if not place_lightworld:
target_doors = lw_doors
target_entrances = lw_entrances
else:
target_doors = dw_doors
target_entrances = dw_entrances
for exit in cave:
ret.append(connect_exit(world, exit, target_entrances.pop()))
ret.append(connect_entrance(world, target_doors.pop(), exit))
# handle simple doors
single_doors = list(Single_Cave_Doors)
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors)
door_targets = list(Single_Cave_Targets)
# place blacksmith, has limited options
random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop()
ret.append(connect_one_way(world, blacksmith_hut, 'Blacksmiths Hut'))
bomb_shop_doors.extend(blacksmith_doors)
# place dam and pyramid fairy, have limited options
# ToDo Dam might be behind fat fairy if we later check for this when placing crystal 5 and 6
random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop()
ret.append(connect_one_way(world, bomb_shop, 'Big Bomb Shop'))
dam = bomb_shop_doors.pop()
ret.append(connect_one_way(world, dam, 'Dam'))
single_doors.extend(bomb_shop_doors)
# tavern back door cannot be shuffled yet
ret.append(connect_doors(world, ['Tavern North'], ['Tavern']))
# place remaining doors
ret.append(connect_doors(world, single_doors, door_targets))
else: else:
raise NotImplementedError('Shuffling not supported yet') raise NotImplementedError('Shuffling not supported yet')
@ -200,6 +525,23 @@ def connect_one_way(world, exitname, regionname):
return '%s => %s' % (entrance.name, region.name) return '%s => %s' % (entrance.name, region.name)
def connect_entrance(world, entrancename, exitname):
entrance = world.get_entrance(entrancename)
exit = world.get_entrance(exitname)
target = (exit_ids[exit.name][0], entrance.target[1] if entrance.target is not None else None)
entrance.connect(exit.parent_region, target)
return '%s => %s' % (entrance.name, exit.name)
def connect_exit(world, exitname, entrancename):
entrance = world.get_entrance(entrancename)
exit = world.get_entrance(exitname)
target = (entrance.target[0] if entrance.target is not None else None, exit_ids[exit.name][1])
entrance.target = target
exit.connect(entrance.parent_region)
return '%s <= %s' % (entrance.name, exit.name)
def connect_two_way(world, entrancename, exitname): def connect_two_way(world, entrancename, exitname):
entrance = world.get_entrance(entrancename) entrance = world.get_entrance(entrancename)
exit = world.get_entrance(exitname) exit = world.get_entrance(exitname)
@ -457,6 +799,13 @@ Dungeon_Exits = [('Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'De
DW_Entrances_Must_Exit = ['Bumper Cave (Top)', 'Hookshot Cave Back Entrance'] DW_Entrances_Must_Exit = ['Bumper Cave (Top)', 'Hookshot Cave Back Entrance']
Two_Door_Caves_Directional = [('Bumper Cave (Bottom)', 'Bumper Cave (Top)'),
('Hookshot Cave', 'Hookshot Cave Back Entrance')]
Two_Door_Caves = [('Elder House (East)', 'Elder House (West)'),
('Two Brothers House (East)', 'Two Brothers House (West)'),
('Dark Death Mountain Climb (Bottom)', 'Dark Death Mountain Climb (Top)')]
Old_Man_Entrances = ['Old Man Cave (East)', Old_Man_Entrances = ['Old Man Cave (East)',
'Old Man House (Top)', 'Old Man House (Top)',
'Death Mountain Return Cave (East)', 'Death Mountain Return Cave (East)',
@ -716,6 +1065,9 @@ mandatory_connections = [('Links House', 'Links House'), # unshuffled. For now
('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'),
('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'),
('Turtle Rock Teleporter', 'Turtle Rock (Top)'), ('Turtle Rock Teleporter', 'Turtle Rock (Top)'),
('Turtle Rock Open Skull', 'Turtle Rock Skull'),
('Turtle Rock Skull Reverse', 'Dark Death Mountain (Top)'),
('Turtle Rock Skull Mirror Spot', 'Turtle Rock (Top)'),
('Turtle Rock Drop', 'Dark Death Mountain (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain (Top)'),
('Floating Island Drop', 'Dark Death Mountain (Top)'), ('Floating Island Drop', 'Dark Death Mountain (Top)'),
('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'),
@ -728,6 +1080,8 @@ mandatory_connections = [('Links House', 'Links House'), # unshuffled. For now
('Swamp Palace (North)', 'Swamp Palace (North)'), ('Swamp Palace (North)', 'Swamp Palace (North)'),
('Thieves Town Big Key Door', 'Thieves Town (Deep)'), ('Thieves Town Big Key Door', 'Thieves Town (Deep)'),
('Skull Woods Torch Room', 'Skull Woods Final Section (Mothula)'), ('Skull Woods Torch Room', 'Skull Woods Final Section (Mothula)'),
('Skull Woods Burn Skull', 'Skull Woods Skull'),
('Skull Woods Skull Reverse', 'Skull Woods Forest (West)'),
('Blind Fight', 'Blind Fight'), ('Blind Fight', 'Blind Fight'),
('Ice Palace Entrance Room', 'Ice Palace (Main)'), ('Ice Palace Entrance Room', 'Ice Palace (Main)'),
('Ice Palace (East)', 'Ice Palace (East)'), ('Ice Palace (East)', 'Ice Palace (East)'),
@ -961,9 +1315,9 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Palace
('Skull Woods Second Section Door (East)', 'Skull Woods Second Section'), ('Skull Woods Second Section Door (East)', 'Skull Woods Second Section'),
('Skull Woods Second Section Door (West)', 'Skull Woods Second Section'), ('Skull Woods Second Section Door (West)', 'Skull Woods Second Section'),
('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'),
('Skull Woods Second Section Exit (West)', 'Skull Woods Forest'), ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'),
('Skull Woods Final Section', 'Skull Woods Final Section (Entrance)'), ('Skull Woods Final Section', 'Skull Woods Final Section (Entrance)'),
('Skull Woods Final Section Exit', 'Skull Woods Forest'), ('Skull Woods Final Section Exit', 'Skull Woods Skull'),
('Ice Palace', 'Ice Palace (Entrance)'), ('Ice Palace', 'Ice Palace (Entrance)'),
('Ice Palace Exit', 'Light World'), # this is kind of wrong, but completely unimportantly so ('Ice Palace Exit', 'Light World'), # this is kind of wrong, but completely unimportantly so
('Misery Mire', 'Misery Mire (Entrance)'), ('Misery Mire', 'Misery Mire (Entrance)'),
@ -1095,8 +1449,8 @@ exit_ids = {'Desert Palace Exit (South)': (0x09, 0x84),
'Spiral Cave Exit (Top)': (0x1D, 0xEE), 'Spiral Cave Exit (Top)': (0x1D, 0xEE),
'Bumper Cave Exit (Top)': (0x17, 0xEB), 'Bumper Cave Exit (Top)': (0x17, 0xEB),
'Bumper Cave Exit (Bottom)': (0x16, 0xFB), 'Bumper Cave Exit (Bottom)': (0x16, 0xFB),
'Dark Death Mountain Climb Exit (Top)': (0x13, 0xF8), 'Dark Death Mountain Climb Exit (Top)': (0x14, 0xE8),
'Dark Death Mountain Climb Exit (Bottom)': (0x14, 0xE8), 'Dark Death Mountain Climb Exit (Bottom)': (0x13, 0xF8),
'Hookshot Cave Exit (South)': (0x3A, 0x3C), 'Hookshot Cave Exit (South)': (0x3A, 0x3C),
'Hookshot Cave Exit (North)': (0x3B, 0x2C)} 'Hookshot Cave Exit (North)': (0x3B, 0x2C)}