Fixed follower logic to use new dynamic mirror connections
This commit is contained in:
@@ -1562,7 +1562,7 @@ class Entrance(object):
|
|||||||
|
|
||||||
def can_reach(self, state):
|
def can_reach(self, state):
|
||||||
# Destination Pickup OW Only No Ledges Can S&Q Allow Mirror
|
# Destination Pickup OW Only No Ledges Can S&Q Allow Mirror
|
||||||
multi_step_locations = { 'Pyramid Area': ('Big Bomb', True, True, False, True),
|
multi_step_locations = { 'Pyramid Crack': ('Big Bomb', True, True, False, True),
|
||||||
'Missing Smith': ('Frog', True, False, True, True),
|
'Missing Smith': ('Frog', True, False, True, True),
|
||||||
'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True, True),
|
'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True, True),
|
||||||
'Old Man Drop Off': ('Lost Old Man', True, False, False, False),
|
'Old Man Drop Off': ('Lost Old Man', True, False, False, False),
|
||||||
@@ -1581,7 +1581,13 @@ class Entrance(object):
|
|||||||
while len(self.temp_path):
|
while len(self.temp_path):
|
||||||
exit = self.temp_path.pop(0)
|
exit = self.temp_path.pop(0)
|
||||||
path = (exit.name, (exit.parent_region.name, path))
|
path = (exit.name, (exit.parent_region.name, path))
|
||||||
item_name = self.connected_region.locations[0].item.name if self.connected_region.locations[0].item else 'Deliver Item'
|
item_name = 'Deliver Item'
|
||||||
|
if len(self.connected_region.locations) > 0 and self.connected_region.locations[0].item:
|
||||||
|
item_name = self.connected_region.locations[0].item.name
|
||||||
|
for loc in self.parent_region.locations:
|
||||||
|
if loc.event and not loc.real and loc.item.name.find('Farmable') < 0:
|
||||||
|
item_name = loc.item.name
|
||||||
|
break
|
||||||
path = (item_name, (self.parent_region.name, path))
|
path = (item_name, (self.parent_region.name, path))
|
||||||
state.path[self] = (self.name, path)
|
state.path[self] = (self.name, path)
|
||||||
return True
|
return True
|
||||||
@@ -1626,45 +1632,39 @@ class Entrance(object):
|
|||||||
exits_to_traverse = list()
|
exits_to_traverse = list()
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
if not found and allow_mirror_reentry and state.has('Magic Mirror', self.player):
|
if not found and allow_mirror_reentry and state.has_Mirror(self.player):
|
||||||
# check for path using mirror portal re-entry at location of the follower pickup
|
# check for path using mirror portal re-entry at location of the follower pickup
|
||||||
# this is checked first as this often the shortest path
|
# this is checked first as this often the shortest path
|
||||||
follower_region = start_region
|
follower_region = start_region
|
||||||
if follower_region.type not in [RegionType.LightWorld, RegionType.DarkWorld]:
|
if follower_region.type not in [RegionType.LightWorld, RegionType.DarkWorld]:
|
||||||
follower_region = [i for i in start_region.entrances if i.parent_region.name != 'Menu'][0].parent_region
|
follower_region = [i for i in start_region.entrances if i.parent_region.name != 'Menu'][0].parent_region
|
||||||
if (follower_region.world.mode[self.player] != 'inverted') == (follower_region.type == RegionType.LightWorld):
|
if (follower_region.world.mode[self.player] != 'inverted') == (follower_region.type == RegionType.LightWorld):
|
||||||
from OWEdges import OWTileRegions
|
from OverworldShuffle import get_mirror_edges
|
||||||
from OverworldShuffle import ow_connections
|
mirror_map = get_mirror_edges(follower_region.world, follower_region, self.player)
|
||||||
owid = OWTileRegions[follower_region.name]
|
while len(mirror_map) and not found:
|
||||||
(mirror_map_orig, other_world) = ow_connections[owid % 0x40]
|
|
||||||
mirror_map = list(mirror_map_orig).copy()
|
|
||||||
mirror_map.extend(other_world)
|
|
||||||
mirror_exit = None
|
|
||||||
while len(mirror_map):
|
|
||||||
if mirror_map[0][1] == follower_region.name:
|
if mirror_map[0][1] == follower_region.name:
|
||||||
mirror_exit = mirror_map[0][0]
|
mirror_exit = mirror_map[0][0]
|
||||||
break
|
mirror_region = follower_region.world.get_entrance(mirror_exit, self.player).parent_region
|
||||||
|
if mirror_exit and mirror_region:
|
||||||
|
if mirror_region.can_reach(state):
|
||||||
|
traverse_paths(mirror_region, self.parent_region)
|
||||||
|
break # no need to continue if there is no path from the mirror re-entry to dest
|
||||||
mirror_map.pop(0)
|
mirror_map.pop(0)
|
||||||
if mirror_exit:
|
if found:
|
||||||
mirror_region = follower_region.world.get_entrance(mirror_exit, self.player).parent_region
|
path = state.path.get(mirror_region, (mirror_region.name, None))
|
||||||
if mirror_region.can_reach(state):
|
path = (follower_region.name, (mirror_exit, path))
|
||||||
traverse_paths(mirror_region, self.parent_region)
|
item_name = step_location.item.name if step_location.item else 'Pick Up Item'
|
||||||
if found:
|
if start_region.name != follower_region.name:
|
||||||
path = state.path.get(mirror_region, (mirror_region.name, None))
|
path = (start_region.name, (start_region.entrances[0].name, path))
|
||||||
path = (follower_region.name, (mirror_exit, path))
|
path = (f'{step_location.parent_region.name} Exit', ('Leave Item Area', (item_name, path)))
|
||||||
item_name = step_location.item.name if step_location.item else 'Pick Up Item'
|
else:
|
||||||
if start_region.name != follower_region.name:
|
path = (item_name, path)
|
||||||
path = (start_region.name, (start_region.entrances[0].name, path))
|
path = ('Use Mirror Portal', (follower_region.name, path))
|
||||||
path = (f'{step_location.parent_region.name} Exit', ('Leave Item Area', (item_name, path)))
|
while len(self.temp_path):
|
||||||
else:
|
exit = self.temp_path.pop(0)
|
||||||
path = (item_name, path)
|
path = (exit.name, (exit.parent_region.name, path))
|
||||||
path = ('Use Mirror Portal', (follower_region.name, path))
|
path = (self.parent_region.name, path)
|
||||||
while len(self.temp_path):
|
state.path[self] = (self.name, path)
|
||||||
exit = self.temp_path.pop(0)
|
|
||||||
path = (exit.name, (exit.parent_region.name, path))
|
|
||||||
item_name = self.connected_region.locations[0].item.name if self.connected_region.locations[0].item else 'Deliver Item'
|
|
||||||
path = (self.parent_region.name, path)
|
|
||||||
state.path[self] = (self.name, path)
|
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
# check normal paths
|
# check normal paths
|
||||||
@@ -1675,7 +1675,7 @@ class Entrance(object):
|
|||||||
exit = self.parent_region.world.get_entrance('Links House S&Q', self.player)
|
exit = self.parent_region.world.get_entrance('Links House S&Q', self.player)
|
||||||
traverse_paths(exit.connected_region, self.parent_region, [exit])
|
traverse_paths(exit.connected_region, self.parent_region, [exit])
|
||||||
|
|
||||||
if not found and allow_mirror_reentry and state.has('Magic Mirror', self.player):
|
if not found and allow_mirror_reentry and state.has_Mirror(self.player):
|
||||||
# check for paths using mirror portal re-entry at location of final destination
|
# check for paths using mirror portal re-entry at location of final destination
|
||||||
# this is checked last as this is the most complicated/exhaustive check
|
# this is checked last as this is the most complicated/exhaustive check
|
||||||
follower_region = start_region
|
follower_region = start_region
|
||||||
@@ -1686,14 +1686,9 @@ class Entrance(object):
|
|||||||
if dest_region.type not in [RegionType.LightWorld, RegionType.DarkWorld]:
|
if dest_region.type not in [RegionType.LightWorld, RegionType.DarkWorld]:
|
||||||
dest_region = start_region.entrances[0].parent_region
|
dest_region = start_region.entrances[0].parent_region
|
||||||
if (dest_region.world.mode[self.player] != 'inverted') != (dest_region.type == RegionType.LightWorld):
|
if (dest_region.world.mode[self.player] != 'inverted') != (dest_region.type == RegionType.LightWorld):
|
||||||
from OWEdges import OWTileRegions
|
|
||||||
from OverworldShuffle import ow_connections
|
|
||||||
owid = OWTileRegions[dest_region.name]
|
|
||||||
(mirror_map_orig, other_world) = ow_connections.copy()[owid % 0x40]
|
|
||||||
mirror_map = list(mirror_map_orig).copy()
|
|
||||||
mirror_map.extend(other_world)
|
|
||||||
mirror_map = [(x, d) for (x, d) in mirror_map if x in [e.name for e in dest_region.exits]]
|
|
||||||
# loop thru potential places to leave a mirror portal
|
# loop thru potential places to leave a mirror portal
|
||||||
|
from OverworldShuffle import get_mirror_edges
|
||||||
|
mirror_map = get_mirror_edges(dest_region.world, dest_region, self.player)
|
||||||
while len(mirror_map) and not found:
|
while len(mirror_map) and not found:
|
||||||
mirror_exit = dest_region.world.get_entrance(mirror_map[0][0], self.player)
|
mirror_exit = dest_region.world.get_entrance(mirror_map[0][0], self.player)
|
||||||
if mirror_exit.connected_region.type != dest_region.type:
|
if mirror_exit.connected_region.type != dest_region.type:
|
||||||
|
|||||||
@@ -837,22 +837,44 @@ def create_flute_exits(world, player):
|
|||||||
exit.connect(world.get_region('Flute Sky', player))
|
exit.connect(world.get_region('Flute Sky', player))
|
||||||
region.exits.append(exit)
|
region.exits.append(exit)
|
||||||
|
|
||||||
|
def get_mirror_exit_name(from_region, to_region):
|
||||||
|
if from_region in mirror_connections and to_region in mirror_connections[from_region]:
|
||||||
|
if len(mirror_connections[from_region]) == 1:
|
||||||
|
return f'Mirror From {from_region}'
|
||||||
|
else:
|
||||||
|
return f'Mirror To {to_region}'
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_mirror_edges(world, region, player):
|
||||||
|
mirror_exits = list()
|
||||||
|
if (world.mode[player] != 'inverted') == (region.type == RegionType.DarkWorld):
|
||||||
|
# get mirror edges leaving the region
|
||||||
|
if region.name in mirror_connections:
|
||||||
|
for dest_region_name in mirror_connections[region.name]:
|
||||||
|
mirror_exits.append(tuple([get_mirror_exit_name(region.name, dest_region_name), dest_region_name]))
|
||||||
|
else:
|
||||||
|
# get mirror edges leading into the region
|
||||||
|
owid = OWTileRegions[region.name]
|
||||||
|
for other_world_region_name in OWTileRegions.inverse[(owid + 0x40) % 0x80]:
|
||||||
|
if other_world_region_name in mirror_connections:
|
||||||
|
for dest_region_name in mirror_connections[other_world_region_name]:
|
||||||
|
if dest_region_name == region.name:
|
||||||
|
mirror_exits.append(tuple([get_mirror_exit_name(other_world_region_name, region.name), region.name]))
|
||||||
|
return mirror_exits
|
||||||
|
|
||||||
def create_mirror_exits(world, player):
|
def create_mirror_exits(world, player):
|
||||||
mirror_exits = set()
|
mirror_exits = set()
|
||||||
for region in (r for r in world.regions if r.player == player and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):
|
for region in (r for r in world.regions if r.player == player and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):
|
||||||
if region.type == (RegionType.DarkWorld if world.mode[player] != 'inverted' else RegionType.LightWorld):
|
if region.type == (RegionType.DarkWorld if world.mode[player] != 'inverted' else RegionType.LightWorld):
|
||||||
if region.name in mirror_connections:
|
if region.name in mirror_connections:
|
||||||
for region_dest_name in mirror_connections[region.name]:
|
for region_dest_name in mirror_connections[region.name]:
|
||||||
to_region = world.get_region(region_dest_name, player)
|
exitname = get_mirror_exit_name(region.name, region_dest_name)
|
||||||
if len(mirror_connections[region.name]) == 1:
|
|
||||||
exitname = 'Mirror From ' + region.name
|
|
||||||
else:
|
|
||||||
exitname = 'Mirror To ' + region_dest_name
|
|
||||||
|
|
||||||
assert(exitname not in mirror_exits, f'Mirror Exit with name already exists: {exitname}')
|
assert exitname not in mirror_exits, f'Mirror Exit with name already exists: {exitname}'
|
||||||
|
|
||||||
exit = Entrance(region.player, exitname, region)
|
exit = Entrance(region.player, exitname, region)
|
||||||
exit.spot_type = 'Mirror'
|
exit.spot_type = 'Mirror'
|
||||||
|
to_region = world.get_region(region_dest_name, player)
|
||||||
if region.terrain == Terrain.Water or to_region.terrain == Terrain.Water:
|
if region.terrain == Terrain.Water or to_region.terrain == Terrain.Water:
|
||||||
exit.access_rule = lambda state: state.has('Flippers', player) and state.has_Pearl(player) and state.has_Mirror(player)
|
exit.access_rule = lambda state: state.has('Flippers', player) and state.has_Pearl(player) and state.has_Mirror(player)
|
||||||
else:
|
else:
|
||||||
@@ -862,7 +884,7 @@ def create_mirror_exits(world, player):
|
|||||||
|
|
||||||
mirror_exits.add(exitname)
|
mirror_exits.add(exitname)
|
||||||
elif region.terrain == Terrain.Land:
|
elif region.terrain == Terrain.Land:
|
||||||
logging.getLogger('').debug(f'Region has no mirror exit: {region.name}')
|
pass
|
||||||
|
|
||||||
def create_dynamic_exits(world, player):
|
def create_dynamic_exits(world, player):
|
||||||
create_flute_exits(world, player)
|
create_flute_exits(world, player)
|
||||||
|
|||||||
Reference in New Issue
Block a user