Replace world exploration with a faster algorithm - use BFS and keep track of all entrances that are currently blocked by progression items.
New algorithm also obsoletes sweep_for_crystal_access Set up door and entrance caches in advance Replace CrystalBarrier with FastEnum for bitfield arithmetic
This commit is contained in:
59
Rules.py
59
Rules.py
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
from BaseClasses import CollectionState, RegionType, DoorType
|
||||
from Regions import key_only_locations
|
||||
from Items import ItemFactory
|
||||
from RoomData import DoorKind
|
||||
from collections import deque
|
||||
|
||||
@@ -9,20 +10,10 @@ def set_rules(world, player):
|
||||
|
||||
if world.logic[player] == 'nologic':
|
||||
logging.getLogger('').info('WARNING! Seeds generated under this logic often require major glitches and may be impossible!')
|
||||
if world.mode[player] != 'inverted':
|
||||
world.get_region('Links House', player).can_reach_private = lambda state: True
|
||||
world.get_region('Sanctuary', player).can_reach_private = lambda state: True
|
||||
old_rule = world.get_region('Old Man House', player).can_reach
|
||||
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
|
||||
return
|
||||
else:
|
||||
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
|
||||
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach_private = lambda state: True
|
||||
if world.shuffle[player] != 'vanilla':
|
||||
old_rule = world.get_region('Old Man House', player).can_reach
|
||||
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
|
||||
world.get_region('Hyrule Castle Ledge', player).can_reach_private = lambda state: True
|
||||
return
|
||||
world.get_region('Menu', player).can_reach_private = lambda state: True
|
||||
for exit in world.get_region('Menu', player).exits:
|
||||
exit.hide_path = True
|
||||
return
|
||||
|
||||
global_rules(world, player)
|
||||
if world.mode[player] != 'inverted':
|
||||
@@ -113,8 +104,11 @@ def global_rules(world, player):
|
||||
add_item_rule(world.get_location('Ganon', player), lambda item: item.name == 'Triforce' and item.player == player)
|
||||
|
||||
# we can s&q to the old man house after we rescue him. This may be somewhere completely different if caves are shuffled!
|
||||
old_rule = world.get_region('Old Man House', player).can_reach_private
|
||||
world.get_region('Old Man House', player).can_reach_private = lambda state: state.can_reach('Old Man', 'Location', player) or old_rule(state)
|
||||
world.get_region('Menu', player).can_reach_private = lambda state: True
|
||||
for exit in world.get_region('Menu', player).exits:
|
||||
exit.hide_path = True
|
||||
|
||||
set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.can_reach('Old Man', 'Location', player))
|
||||
|
||||
set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
|
||||
set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player))
|
||||
@@ -384,16 +378,6 @@ def global_rules(world, player):
|
||||
|
||||
|
||||
def default_rules(world, player):
|
||||
if world.mode[player] == 'standard':
|
||||
# Links house requires reaching Sanc so skipping that chest isn't a softlock.
|
||||
world.get_region('Hyrule Castle Secret Entrance', player).can_reach_private = lambda state: True
|
||||
old_rule = world.get_region('Links House', player).can_reach_private
|
||||
world.get_region('Links House', player).can_reach_private = lambda state: state.has('Zelda Delivered', player) or old_rule(state)
|
||||
else:
|
||||
# these are default save&quit points and always accessible
|
||||
world.get_region('Links House', player).can_reach_private = lambda state: True
|
||||
world.get_region('Sanctuary', player).can_reach_private = lambda state: True
|
||||
|
||||
# overworld requirements
|
||||
set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player))
|
||||
set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player))
|
||||
@@ -506,12 +490,7 @@ def default_rules(world, player):
|
||||
|
||||
def inverted_rules(world, player):
|
||||
# s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached
|
||||
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
|
||||
world.get_region('Inverted Links House', player).entrances[0].can_reach = lambda state: True
|
||||
world.get_region('Inverted Dark Sanctuary', player).entrances[0].parent_region.can_reach_private = lambda state: True
|
||||
|
||||
old_rule = world.get_region('Hyrule Castle Ledge', player).can_reach_private
|
||||
world.get_region('Hyrule Castle Ledge', player).can_reach_private = lambda state: (state.has_Mirror(player) and state.has('Beat Agahnim 1', player) and state.can_reach_light_world(player)) or old_rule(state)
|
||||
set_rule(world.get_entrance('Castle Ledge S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player))
|
||||
|
||||
# overworld requirements
|
||||
set_rule(world.get_location('Maze Race', player), lambda state: state.has_Pearl(player))
|
||||
@@ -824,7 +803,19 @@ std_kill_rooms = {
|
||||
} # all trap rooms?
|
||||
|
||||
|
||||
def add_connection(parent_name, target_name, entrance_name, world, player):
|
||||
parent = world.get_region(parent_name, player)
|
||||
target = world.get_region(target_name, player)
|
||||
connection = Entrance(player, entrance_name, parent)
|
||||
parent.exits.append(connection)
|
||||
connection.connect(target)
|
||||
|
||||
|
||||
def standard_rules(world, player):
|
||||
add_connection('Menu', 'Hyrule Castle Secret Entrance', 'Uncle S&Q', world, player)
|
||||
world.get_entrance('Uncle S&Q', player).hide_path = True
|
||||
set_rule(world.get_entrance('Links House S&Q', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
|
||||
set_rule(world.get_entrance('Sanctuary S&Q', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
|
||||
# these are because of rails
|
||||
if world.shuffle[player] != 'vanilla':
|
||||
set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.has('Zelda Delivered', player))
|
||||
@@ -1039,7 +1030,7 @@ def set_big_bomb_rules(world, player):
|
||||
# the basic routes assume you can reach eastern light world with the bomb.
|
||||
# you can then use the southern teleporter, or (if you have beaten Aga1) the hyrule castle gate warp
|
||||
def basic_routes(state):
|
||||
return southern_teleporter(state) or state.can_reach('Top of Pyramid', 'Entrance', player)
|
||||
return southern_teleporter(state) or state.has('Beat Agahnim 1', player)
|
||||
|
||||
# Key for below abbreviations:
|
||||
# P = pearl
|
||||
@@ -1072,7 +1063,7 @@ def set_big_bomb_rules(world, player):
|
||||
#1. Mirror and enter via gate: Need mirror and Aga1
|
||||
#2. cross peg bridge: Need hammer and moon pearl
|
||||
# -> CPB or (M and A)
|
||||
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: cross_peg_bridge(state) or (state.has_Mirror(player) and state.can_reach('Top of Pyramid', 'Entrance', player)))
|
||||
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: cross_peg_bridge(state) or (state.has_Mirror(player) and state.has('Beat Agahnim 1', player)))
|
||||
elif bombshop_entrance.name in Isolated_DW_entrances:
|
||||
# 1. mirror then flute then basic routes
|
||||
# -> M and Flute and BR
|
||||
|
||||
Reference in New Issue
Block a user