300 lines
11 KiB
Python
300 lines
11 KiB
Python
"""
|
|
Helper functions to deliver entrance/exit/region sets to OWG rules.
|
|
"""
|
|
|
|
from BaseClasses import Entrance, Region
|
|
|
|
# Cave regions that superbunny can get through - but only with a sword.
|
|
sword_required_superbunny_mirror_regions = ["Spiral Cave (Top)"]
|
|
|
|
# Cave regions that superbunny can get through - but only with boots.
|
|
boots_required_superbunny_mirror_regions = ["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",
|
|
]
|
|
|
|
# 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
|
|
|
|
|
|
# Entrances that can be reached with full equipment using overworld glitches and don't need to be an exit.
|
|
# The following are still be mandatory exits:
|
|
# Open:
|
|
# Turtle Rock Isolated Ledge Entrance
|
|
# Skull Woods Second Section Door (West) (or Skull Woods Final Section)
|
|
# Inverted:
|
|
# Two Brothers House (West)
|
|
# Desert Palace Entrance (East)
|
|
|
|
|
|
non_mandatory_exits = [
|
|
"Bumper Cave (Top)",
|
|
"Death Mountain Return Cave (West)",
|
|
"Hookshot Cave Back Entrance",
|
|
]
|
|
|
|
inverted_non_mandatory_exits = [
|
|
"Desert Palace Entrance (North)",
|
|
"Desert Palace Entrance (West)",
|
|
"Agahnims Tower",
|
|
"Hyrule Castle Entrance (West)",
|
|
"Hyrule Castle Entrance (East)",
|
|
] + non_mandatory_exits
|
|
|
|
open_non_mandatory_exits = [
|
|
"Dark Death Mountain Ledge (West)",
|
|
"Dark Death Mountain Ledge (East)",
|
|
"Mimic Cave",
|
|
"Desert Palace Entrance (East)",
|
|
] + non_mandatory_exits
|
|
|
|
|
|
# Special Light World region exits that require boots clips.
|
|
boots_clip_exits_lw = [
|
|
('Lumberjack DMA Clip', 'Lumberjack Area', 'West Death Mountain (Bottom)'),
|
|
('Spectacle Rock Clip', 'West Death Mountain (Top)', 'Spectacle Rock Ledge'),
|
|
('Hera Ascent Clip', 'West Death Mountain (Bottom)', 'West Death Mountain (Top)'),
|
|
('Death Mountain Glitched Bridge Clip', 'West Death Mountain (Bottom)', 'East Death Mountain (Top East)'),
|
|
('Sanctuary DMD Clip', 'West Death Mountain (Bottom)', 'Sanctuary Area'),
|
|
('Graveyard Ledge Clip', 'West Death Mountain (Bottom)', 'Graveyard Ledge'),
|
|
('Kings Grave Clip', 'West Death Mountain (Bottom)', 'Kings Grave Area'),
|
|
('Floating Island Clip', 'East Death Mountain (Top East)', 'Death Mountain Floating Island'),
|
|
('Zora DMD Clip', 'Death Mountain TR Pegs Area', 'Zoras Domain'),
|
|
('TR Pegs Ledge Clip', 'Death Mountain TR Pegs Area', 'Death Mountain TR Pegs Ledge'),
|
|
('Mountain Pass Ledge Clip', 'Mountain Pass Area', 'Mountain Pass Ledge'),
|
|
('Mountain Pass Entry Clip', 'Kakariko Pond Area', 'Mountain Pass Entry'),
|
|
('Desert Keep Clip', 'Maze Race Area', 'Desert Ledge Keep'),
|
|
('Desert Ledge Clip', 'Maze Race Area', 'Desert Ledge'),
|
|
('Maze Race Prize Clip', 'Maze Race Area', 'Maze Race Prize'),
|
|
('Stone Bridge To Cliff Clip', 'Stone Bridge South Area', 'Central Cliffs'),
|
|
('Hobo Clip', 'Stone Bridge South Area', 'Stone Bridge Water'),
|
|
('Bombos Tablet Clip', 'Desert Area', 'Bombos Tablet Ledge'),
|
|
('Desert Teleporter Clip', 'Desert Area', 'Desert Teleporter Ledge'),
|
|
('Cave 45 Clip', 'Flute Boy Approach Area', 'Cave 45 Ledge'),
|
|
('Desert Northern Cliffs Clip', 'Flute Boy Approach Area', 'Desert Northern Cliffs')
|
|
]
|
|
|
|
# Special Dark World region exits that require boots clips.
|
|
boots_clip_exits_dw = [
|
|
('Dark World DMA Clip', 'Dark Lumberjack Area', 'West Dark Death Mountain (Bottom)'),
|
|
('Dark Death Mountain Descent', 'West Dark Death Mountain (Bottom)', 'Dark Chapel Area'),
|
|
('Ganons Tower Ascent', 'West Dark Death Mountain (Bottom)', 'GT Stairs'), # This only gets you to the GT entrance
|
|
('Dark Death Mountain Glitched Bridge', 'West Dark Death Mountain (Bottom)', 'East Dark Death Mountain (Top)'),
|
|
('DW Floating Island Clip', 'East Dark Death Mountain (Bottom)', 'Dark Death Mountain Floating Island'),
|
|
('Turtle Rock (Top) Clip', 'Turtle Rock Area', 'Turtle Rock Ledge'),
|
|
('Catfish DMD', 'Turtle Rock Area', 'Catfish Area'),
|
|
('Bumper Cave Ledge Clip', 'Bumper Cave Area', 'Bumper Cave Ledge'),
|
|
('Bumper Cave Entry Clip', 'Outcast Pond Area', 'Bumper Cave Entry'),
|
|
('Broken Bridge Hammer Rock Skip Clip', 'Qirn Jump East Bank', 'Broken Bridge Area'),
|
|
('Dark Witch Rock Skip Clip', 'Dark Witch Area', 'Dark Witch Northeast'),
|
|
('Hammer Pegs River Clip', 'Dark Dunes Area', 'Hammer Pegs Area'),
|
|
('Hammer Bridge To Cliff Clip', 'Hammer Bridge South Area', 'Dark Central Cliffs'),
|
|
('Mire Cliffs Clip', 'Stumpy Approach Area', 'Mire Northern Cliffs'),
|
|
('Dark Lake Hylia Ledge Clip', 'Darkness Nook Area', 'Shopping Mall Area'),
|
|
('Mire Teleporter Clip', 'Mire Area', 'Mire Teleporter Ledge')
|
|
]
|
|
|
|
|
|
# Dark World drop-down ledges that require glitched speed.
|
|
glitched_speed_drops_dw = [
|
|
('Dark Death Mountain Ledge Clip', 'East Dark Death Mountain (Top)', 'Dark Death Mountain Ledge')
|
|
]
|
|
|
|
|
|
# Out of bounds transitions using the mirror
|
|
mirror_clip_spots_dw = [
|
|
('Bunny DMD Mirror Spot', 'West Dark Death Mountain (Bottom)', 'Qirn Jump Area'),
|
|
(
|
|
'Dark Death Mountain Bunny Mirror To East Jump',
|
|
'West Dark Death Mountain (Bottom)',
|
|
'East Dark Death Mountain (Bottom)',
|
|
),
|
|
('Desert East Mirror Clip', 'Mire Area', 'Desert Mouth'),
|
|
]
|
|
|
|
# Mirror shenanigans placing a mirror portal with a broken camera
|
|
mirror_offset_spots_dw = [('Dark Death Mountain Offset Mirror', 'West Dark Death Mountain (Bottom)', 'Pyramid Area')]
|
|
|
|
# Mirror shenanigans placing a mirror portal with a broken camera
|
|
mirror_offset_spots_lw = [
|
|
('Death Mountain Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Area'),
|
|
('Death Mountain Uncle Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Courtyard Northeast'),
|
|
('Death Mountain Castle Ledge Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Ledge'),
|
|
]
|
|
|
|
|
|
def create_owg_connections(world, player):
|
|
"""
|
|
Add OWG transitions to player's world without logic
|
|
"""
|
|
if world.mode[player] == "inverted":
|
|
connections = (
|
|
boots_clip_exits_dw
|
|
+ boots_clip_exits_lw
|
|
+ glitched_speed_drops_dw
|
|
+ mirror_offset_spots_lw
|
|
)
|
|
else:
|
|
connections = (
|
|
boots_clip_exits_dw
|
|
+ boots_clip_exits_lw
|
|
+ glitched_speed_drops_dw
|
|
+ mirror_clip_spots_dw
|
|
+ mirror_offset_spots_dw
|
|
)
|
|
create_no_logic_connections(player, world, connections)
|
|
|
|
|
|
def overworld_glitches_rules(world, player):
|
|
inverted = world.mode[player] == "inverted"
|
|
|
|
# Boots-accessible locations.
|
|
set_owg_rules(
|
|
player,
|
|
world,
|
|
boots_clip_exits_lw,
|
|
lambda state: state.can_boots_clip_lw(player),
|
|
)
|
|
set_owg_rules(
|
|
player,
|
|
world,
|
|
boots_clip_exits_dw,
|
|
lambda state: state.can_boots_clip_dw(player),
|
|
)
|
|
# Glitched speed drops.
|
|
set_owg_rules(
|
|
player,
|
|
world,
|
|
glitched_speed_drops_dw,
|
|
lambda state: state.can_get_glitched_speed_dw(player),
|
|
)
|
|
# Dark Death Mountain Ledge Clip also accessible with mirror.
|
|
if not inverted:
|
|
add_alternate_rule(
|
|
world.get_entrance('Dark Death Mountain Ledge Clip', player), lambda state: state.has_Mirror(player)
|
|
)
|
|
|
|
# Mirror clip spots.
|
|
if inverted:
|
|
set_owg_rules(
|
|
player,
|
|
world,
|
|
mirror_offset_spots_lw,
|
|
lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player),
|
|
)
|
|
else:
|
|
set_owg_rules(player, world, mirror_clip_spots_dw, lambda state: state.has_Mirror(player))
|
|
set_owg_rules(
|
|
player,
|
|
world,
|
|
mirror_offset_spots_dw,
|
|
lambda state: state.has_Mirror(player) and state.can_boots_clip_lw(player),
|
|
)
|
|
|
|
# Regions that require the boots and some other stuff.
|
|
if not inverted:
|
|
add_alternate_rule(
|
|
world.get_entrance('Zora Waterfall Approach', player),
|
|
lambda state: state.has_Pearl(player) or state.has_Boots(player),
|
|
) # assumes access to Waterwalk ability (boots case)
|
|
else:
|
|
add_alternate_rule(
|
|
world.get_entrance('Zora Waterfall Approach', player),
|
|
lambda state: state.has_Pearl(player)
|
|
)
|
|
|
|
add_alternate_rule(
|
|
world.get_location("Zora's Ledge", player), lambda state: state.can_boots_clip_lw(player)
|
|
) # assumes access to Waterwalk ability
|
|
|
|
# Bunny pocket
|
|
if not inverted:
|
|
add_alternate_rule(world.get_entrance("Skull Woods Final Section", player), lambda state: state.can_bunny_pocket(player) and state.has("Fire Rod", player))
|
|
add_alternate_rule(world.get_entrance("Dark World Shop", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
|
|
|
|
|
|
def add_alternate_rule(entrance, rule):
|
|
old_rule = entrance.access_rule
|
|
entrance.access_rule = lambda state: old_rule(state) or rule(state)
|
|
|
|
def create_no_logic_connections(player, world, connections):
|
|
for entrance, parent_region, target_region, *rule_override in connections:
|
|
parent = world.get_region(parent_region, player)
|
|
target = world.get_region(target_region, player)
|
|
connection = Entrance(player, entrance, parent)
|
|
connection.spot_type = 'OWG'
|
|
parent.exits.append(connection)
|
|
connection.connect(target)
|
|
|
|
|
|
def set_owg_rules(player, world, connections, default_rule):
|
|
for entrance, parent_region, target_region, *rule_override in connections:
|
|
connection = world.get_entrance(entrance, player)
|
|
rule = rule_override[0] if len(rule_override) > 0 else default_rule
|
|
connection.access_rule = rule
|