Fixed Swordless rules
Added rule for Freezor chest (for crossed and swordless) Added more "single exit" caves to possible inaccessible regions Prevented dungeon gen from assuming you could get GT Big Key at Aga 2 Prevented cross-dungeon contamination during key rule gen Fixed some key-sphere merging problems (I'm ready to get rid of spheres now)
This commit is contained in:
@@ -303,7 +303,7 @@ def within_dungeon(world, player):
|
|||||||
sector_queue.append((key, sector_list, entrance_list))
|
sector_queue.append((key, sector_list, entrance_list))
|
||||||
last_key = key
|
last_key = key
|
||||||
else:
|
else:
|
||||||
ds = generate_dungeon(sector_list, origin_list_sans_drops, split_dungeon, world, player)
|
ds = generate_dungeon(key, sector_list, origin_list_sans_drops, split_dungeon, world, player)
|
||||||
find_new_entrances(ds, connections, potentials, enabled_entrances, world, player)
|
find_new_entrances(ds, connections, potentials, enabled_entrances, world, player)
|
||||||
ds.name = key
|
ds.name = key
|
||||||
layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list
|
layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list
|
||||||
@@ -1120,7 +1120,7 @@ def find_inaccessible_regions(world, player):
|
|||||||
|
|
||||||
|
|
||||||
def valid_inaccessible_region(r):
|
def valid_inaccessible_region(r):
|
||||||
return r.type is not RegionType.Cave or len(r.exits) > 1 or r.name in ['Spiral Cave (Bottom)']
|
return r.type is not RegionType.Cave or (len(r.exits) > 0 and r.name not in ['Links House', 'Chris Houlihan Room'])
|
||||||
|
|
||||||
|
|
||||||
def add_inaccessible_doors(world, player):
|
def add_inaccessible_doors(world, player):
|
||||||
@@ -1178,7 +1178,8 @@ def check_required_paths(paths, world, player):
|
|||||||
start_regions = convert_regions(start_regs, world, player)
|
start_regions = convert_regions(start_regs, world, player)
|
||||||
initial = start_regs == tuple(entrances)
|
initial = start_regs == tuple(entrances)
|
||||||
if not initial or cached_initial_state is None:
|
if not initial or cached_initial_state is None:
|
||||||
state = ExplorationState(determine_init_crystal(initial, cached_initial_state, start_regions))
|
init = determine_init_crystal(initial, cached_initial_state, start_regions)
|
||||||
|
state = ExplorationState(init, dungeon_name)
|
||||||
for region in start_regions:
|
for region in start_regions:
|
||||||
state.visit_region(region)
|
state.visit_region(region)
|
||||||
state.add_all_doors_check_unattached(region, world, player)
|
state.add_all_doors_check_unattached(region, world, player)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class GraphPiece:
|
|||||||
self.possible_bk_locations = set()
|
self.possible_bk_locations = set()
|
||||||
|
|
||||||
|
|
||||||
def generate_dungeon(available_sectors, entrance_region_names, split_dungeon, world, player):
|
def generate_dungeon(name, available_sectors, entrance_region_names, split_dungeon, world, player):
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
entrance_regions = convert_regions(entrance_region_names, world, player)
|
entrance_regions = convert_regions(entrance_region_names, world, player)
|
||||||
doors_to_connect = set()
|
doors_to_connect = set()
|
||||||
@@ -52,7 +52,7 @@ def generate_dungeon(available_sectors, entrance_region_names, split_dungeon, wo
|
|||||||
if itr > 5000:
|
if itr > 5000:
|
||||||
raise Exception('Generation taking too long. Ref %s' % entrance_region_names[0])
|
raise Exception('Generation taking too long. Ref %s' % entrance_region_names[0])
|
||||||
if depth not in dungeon_cache.keys():
|
if depth not in dungeon_cache.keys():
|
||||||
dungeon, hangers, hooks = gen_dungeon_info(available_sectors, entrance_regions, proposed_map, doors_to_connect, bk_needed, world, player)
|
dungeon, hangers, hooks = gen_dungeon_info(name, available_sectors, entrance_regions, proposed_map, doors_to_connect, bk_needed, world, player)
|
||||||
dungeon_cache[depth] = dungeon, hangers, hooks
|
dungeon_cache[depth] = dungeon, hangers, hooks
|
||||||
valid = check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_regions, bk_needed)
|
valid = check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_regions, bk_needed)
|
||||||
else:
|
else:
|
||||||
@@ -109,10 +109,10 @@ def determine_if_bk_needed(sector, split_dungeon, world, player):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_doors, bk_needed, world, player):
|
def gen_dungeon_info(name, available_sectors, entrance_regions, proposed_map, valid_doors, bk_needed, world, player):
|
||||||
# step 1 create dungeon: Dict<DoorName|Origin, GraphPiece>
|
# step 1 create dungeon: Dict<DoorName|Origin, GraphPiece>
|
||||||
dungeon = {}
|
dungeon = {}
|
||||||
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(), proposed_map, valid_doors, bk_needed, world, player)
|
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(dungeon=name), proposed_map, valid_doors, bk_needed, world, player)
|
||||||
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
|
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
|
||||||
doors_to_connect = set()
|
doors_to_connect = set()
|
||||||
hanger_set = set()
|
hanger_set = set()
|
||||||
@@ -123,7 +123,7 @@ def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_do
|
|||||||
if not door.stonewall and door not in proposed_map.keys():
|
if not door.stonewall and door not in proposed_map.keys():
|
||||||
hanger_set.add(door)
|
hanger_set.add(door)
|
||||||
parent = parent_region(door, world, player).parent_region
|
parent = parent_region(door, world, player).parent_region
|
||||||
o_state = extend_reachable_state_improved([parent], ExplorationState(), proposed_map, valid_doors, False, world, player)
|
o_state = extend_reachable_state_improved([parent], ExplorationState(dungeon=name), proposed_map, valid_doors, False, world, player)
|
||||||
o_state_cache[door.name] = o_state
|
o_state_cache[door.name] = o_state
|
||||||
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
|
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
|
||||||
dungeon[door.name] = piece
|
dungeon[door.name] = piece
|
||||||
@@ -182,7 +182,7 @@ def check_blue_states(hanger_set, dungeon, o_state_cache, proposed_map, valid_do
|
|||||||
|
|
||||||
def explore_blue_state(door, dungeon, o_state, proposed_map, valid_doors, world, player):
|
def explore_blue_state(door, dungeon, o_state, proposed_map, valid_doors, world, player):
|
||||||
parent = parent_region(door, world, player).parent_region
|
parent = parent_region(door, world, player).parent_region
|
||||||
blue_start = ExplorationState(CrystalBarrier.Blue)
|
blue_start = ExplorationState(CrystalBarrier.Blue, o_state.dungeon)
|
||||||
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, False, world, player)
|
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, False, world, player)
|
||||||
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
|
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
|
||||||
|
|
||||||
@@ -257,6 +257,8 @@ def check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_reg
|
|||||||
true_origin_hooks = [x for x in dungeon['Origin'].hooks.keys() if not x.bigKey or possible_bks > 0 or not bk_needed]
|
true_origin_hooks = [x for x in dungeon['Origin'].hooks.keys() if not x.bigKey or possible_bks > 0 or not bk_needed]
|
||||||
if len(true_origin_hooks) == 0 and len(proposed_map.keys()) < len(doors_to_connect):
|
if len(true_origin_hooks) == 0 and len(proposed_map.keys()) < len(doors_to_connect):
|
||||||
return False
|
return False
|
||||||
|
if len(true_origin_hooks) == 0 and bk_needed and possible_bks == 0 and len(proposed_map.keys()) == len(doors_to_connect):
|
||||||
|
return False
|
||||||
for key in hangers.keys():
|
for key in hangers.keys():
|
||||||
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
|
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
|
||||||
return False
|
return False
|
||||||
@@ -374,7 +376,7 @@ def create_graph_piece_from_state(door, o_state, b_state, proposed_map):
|
|||||||
|
|
||||||
|
|
||||||
def filter_for_potential_bk_locations(locations):
|
def filter_for_potential_bk_locations(locations):
|
||||||
return [x for x in locations if '- Big Chest' not in x.name and '- Prize' not in x.name and x.name not in dungeon_events and x.name not in key_only_locations.keys()]
|
return [x for x in locations if '- Big Chest' not in x.name and '- Prize' not in x.name and x.name not in dungeon_events and x.name not in key_only_locations.keys() and x.name not in ['Agahnim 1', 'Agahnim 2']]
|
||||||
|
|
||||||
|
|
||||||
def parent_region(door, world, player):
|
def parent_region(door, world, player):
|
||||||
@@ -498,7 +500,7 @@ def connect_simple_door(exit_door, region, world, player):
|
|||||||
|
|
||||||
class ExplorationState(object):
|
class ExplorationState(object):
|
||||||
|
|
||||||
def __init__(self, init_crystal=CrystalBarrier.Orange):
|
def __init__(self, init_crystal=CrystalBarrier.Orange, dungeon=None):
|
||||||
|
|
||||||
self.unattached_doors = []
|
self.unattached_doors = []
|
||||||
self.avail_doors = []
|
self.avail_doors = []
|
||||||
@@ -527,9 +529,10 @@ class ExplorationState(object):
|
|||||||
self.bk_found = set()
|
self.bk_found = set()
|
||||||
|
|
||||||
self.non_door_entrances = []
|
self.non_door_entrances = []
|
||||||
|
self.dungeon = dungeon
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
ret = ExplorationState()
|
ret = ExplorationState(dungeon=self.dungeon)
|
||||||
ret.unattached_doors = list(self.unattached_doors)
|
ret.unattached_doors = list(self.unattached_doors)
|
||||||
ret.avail_doors = list(self.avail_doors)
|
ret.avail_doors = list(self.avail_doors)
|
||||||
ret.event_doors = list(self.event_doors)
|
ret.event_doors = list(self.event_doors)
|
||||||
@@ -570,21 +573,22 @@ class ExplorationState(object):
|
|||||||
self.visited_orange.append(region)
|
self.visited_orange.append(region)
|
||||||
elif self.crystal == CrystalBarrier.Blue:
|
elif self.crystal == CrystalBarrier.Blue:
|
||||||
self.visited_blue.append(region)
|
self.visited_blue.append(region)
|
||||||
for location in region.locations:
|
if region.type == RegionType.Dungeon:
|
||||||
if key_checks and location not in self.found_locations:
|
for location in region.locations:
|
||||||
if location.name in key_only_locations:
|
if key_checks and location not in self.found_locations:
|
||||||
self.key_locations += 1
|
if location.name in key_only_locations:
|
||||||
if location.name not in dungeon_events and '- Prize' not in location.name:
|
self.key_locations += 1
|
||||||
self.ttl_locations += 1
|
if location.name not in dungeon_events and '- Prize' not in location.name:
|
||||||
if location not in self.found_locations:
|
self.ttl_locations += 1
|
||||||
self.found_locations.append(location)
|
if location not in self.found_locations:
|
||||||
if not bk_Flag:
|
self.found_locations.append(location)
|
||||||
self.bk_found.add(location)
|
if not bk_Flag:
|
||||||
if location.name in dungeon_events and location.name not in self.events:
|
self.bk_found.add(location)
|
||||||
if self.flooded_key_check(location):
|
if location.name in dungeon_events and location.name not in self.events:
|
||||||
self.perform_event(location.name, key_region)
|
if self.flooded_key_check(location):
|
||||||
if location.name in flooded_keys_reverse.keys() and self.location_found(flooded_keys_reverse[location.name]):
|
self.perform_event(location.name, key_region)
|
||||||
self.perform_event(flooded_keys_reverse[location.name], key_region)
|
if location.name in flooded_keys_reverse.keys() and self.location_found(flooded_keys_reverse[location.name]):
|
||||||
|
self.perform_event(flooded_keys_reverse[location.name], key_region)
|
||||||
if key_checks and region.name == 'Hyrule Dungeon Cellblock' and not self.big_key_opened:
|
if key_checks and region.name == 'Hyrule Dungeon Cellblock' and not self.big_key_opened:
|
||||||
self.big_key_opened = True
|
self.big_key_opened = True
|
||||||
self.avail_doors.extend(self.big_doors)
|
self.avail_doors.extend(self.big_doors)
|
||||||
@@ -720,7 +724,7 @@ class ExplorationState(object):
|
|||||||
return cnt
|
return cnt
|
||||||
|
|
||||||
def validate(self, door, region, world, player):
|
def validate(self, door, region, world, player):
|
||||||
return self.can_traverse(door) and not self.visited(region) and valid_region_to_explore(region, world, player)
|
return self.can_traverse(door) and not self.visited(region) and valid_region_to_explore(region, self.dungeon, world, player)
|
||||||
|
|
||||||
def in_door_list(self, door, door_list):
|
def in_door_list(self, door, door_list):
|
||||||
for d in door_list:
|
for d in door_list:
|
||||||
@@ -771,6 +775,7 @@ class ExplorableDoor(object):
|
|||||||
return '%s (%s)' % (self.door.name, self.crystal.name)
|
return '%s (%s)' % (self.door.name, self.crystal.name)
|
||||||
|
|
||||||
|
|
||||||
|
# todo: delete this
|
||||||
def extend_reachable_state(search_regions, state, world, player):
|
def extend_reachable_state(search_regions, state, world, player):
|
||||||
local_state = state.copy()
|
local_state = state.copy()
|
||||||
for region in search_regions:
|
for region in search_regions:
|
||||||
@@ -780,7 +785,7 @@ def extend_reachable_state(search_regions, state, world, player):
|
|||||||
explorable_door = local_state.next_avail_door()
|
explorable_door = local_state.next_avail_door()
|
||||||
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
|
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
|
||||||
if connect_region is not None:
|
if connect_region is not None:
|
||||||
if valid_region_to_explore(connect_region, world, player) and not local_state.visited(connect_region):
|
if valid_region_to_explore(connect_region, local_state.dungeon, world, player) and not local_state.visited(connect_region):
|
||||||
local_state.visit_region(connect_region)
|
local_state.visit_region(connect_region)
|
||||||
local_state.add_all_doors_check_unattached(connect_region, world, player)
|
local_state.add_all_doors_check_unattached(connect_region, world, player)
|
||||||
return local_state
|
return local_state
|
||||||
@@ -801,7 +806,7 @@ def extend_reachable_state_improved(search_regions, state, proposed_map, valid_d
|
|||||||
else:
|
else:
|
||||||
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
|
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
|
||||||
if connect_region is not None:
|
if connect_region is not None:
|
||||||
if valid_region_to_explore(connect_region, world, player) and not local_state.visited(connect_region):
|
if valid_region_to_explore(connect_region, local_state.dungeon, world, player) and not local_state.visited(connect_region):
|
||||||
flag = explorable_door.flag or explorable_door.door.bigKey
|
flag = explorable_door.flag or explorable_door.door.bigKey
|
||||||
local_state.visit_region(connect_region, bk_Flag=flag)
|
local_state.visit_region(connect_region, bk_Flag=flag)
|
||||||
local_state.add_all_doors_check_proposed(connect_region, proposed_map, valid_doors, flag, world, player)
|
local_state.add_all_doors_check_proposed(connect_region, proposed_map, valid_doors, flag, world, player)
|
||||||
@@ -809,8 +814,10 @@ def extend_reachable_state_improved(search_regions, state, proposed_map, valid_d
|
|||||||
|
|
||||||
|
|
||||||
# cross-utility methods
|
# cross-utility methods
|
||||||
def valid_region_to_explore(region, world, player):
|
def valid_region_to_explore(region, name, world, player):
|
||||||
return region is not None and (region.type == RegionType.Dungeon or region.name in world.inaccessible_regions[player])
|
if region is None:
|
||||||
|
return False
|
||||||
|
return (region.type == RegionType.Dungeon and region.dungeon.name == name) or region.name in world.inaccessible_regions[player]
|
||||||
|
|
||||||
|
|
||||||
def get_doors(world, region, player):
|
def get_doors(world, region, player):
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ class KeySphere(object):
|
|||||||
return False
|
return False
|
||||||
if len(set(self.key_only_locations).symmetric_difference(set(other.key_only_locations))) > 0:
|
if len(set(self.key_only_locations).symmetric_difference(set(other.key_only_locations))) > 0:
|
||||||
return False
|
return False
|
||||||
# they only differ in child doors - I don't care
|
if len(set(self.child_doors).symmetric_difference(set(other.child_doors))) > 0:
|
||||||
# if len(set(self.child_doors).symmetric_difference(set(other.child_doors))) > 0:
|
return False
|
||||||
# return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -156,7 +155,7 @@ def analyze_dungeon(key_layout, world, player):
|
|||||||
|
|
||||||
find_bk_locked_sections(key_layout, world)
|
find_bk_locked_sections(key_layout, world)
|
||||||
|
|
||||||
init_bk = check_special_locations(key_layout.key_spheres['Origin'].free_locations)
|
init_bk = check_special_locations(key_layout.key_spheres['Origin'].free_locations.keys())
|
||||||
key_counter = key_layout.key_counters[counter_id({}, init_bk, key_layout.flat_prop)]
|
key_counter = key_layout.key_counters[counter_id({}, init_bk, key_layout.flat_prop)]
|
||||||
queue = collections.deque([(key_layout.key_spheres['Origin'], key_counter)])
|
queue = collections.deque([(key_layout.key_spheres['Origin'], key_counter)])
|
||||||
doors_completed = set()
|
doors_completed = set()
|
||||||
@@ -473,7 +472,7 @@ def expand_counter_no_big_doors(door, key_counter, key_layout, ignored_doors):
|
|||||||
def create_key_spheres(key_layout, world, player):
|
def create_key_spheres(key_layout, world, player):
|
||||||
key_spheres = {}
|
key_spheres = {}
|
||||||
flat_proposal = key_layout.flat_prop
|
flat_proposal = key_layout.flat_prop
|
||||||
state = ExplorationState()
|
state = ExplorationState(dungeon=key_layout.sector.name)
|
||||||
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
||||||
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
@@ -498,12 +497,19 @@ def create_key_spheres(key_layout, world, player):
|
|||||||
if empty_sphere(old_sphere) and not empty_sphere(child_kr):
|
if empty_sphere(old_sphere) and not empty_sphere(child_kr):
|
||||||
key_spheres[door.name] = merge_sphere = child_kr
|
key_spheres[door.name] = merge_sphere = child_kr
|
||||||
queue.append((child_kr, child_state))
|
queue.append((child_kr, child_state))
|
||||||
merge_sphere.bk_locked = old_sphere.bk_locked and child_kr.bk_locked
|
|
||||||
if not empty_sphere(old_sphere) and not empty_sphere(child_kr) and not old_sphere == child_kr:
|
if not empty_sphere(old_sphere) and not empty_sphere(child_kr) and not old_sphere == child_kr:
|
||||||
# ugly sphere merge function - just union locations - ugh
|
# ugly sphere merge function - just union locations - ugh
|
||||||
merge_sphere.free_locations = {**old_sphere.free_locations, **child_kr.free_locations}
|
if old_sphere.bk_locked != child_kr.bk_locked:
|
||||||
merge_sphere.key_only_locations = {**old_sphere.key_only_locations, **child_kr.key_only_locations}
|
if old_sphere.bk_locked:
|
||||||
# this feels so ugly, key counters are much smarter than this - would love to get rid of spheres
|
merge_sphere.child_doors = child_kr.child_doors
|
||||||
|
merge_sphere.free_locations = child_kr.free_locations
|
||||||
|
merge_sphere.key_only_locations = child_kr.key_only_locations
|
||||||
|
else:
|
||||||
|
merge_sphere.child_doors = {**old_sphere.child_doors, **child_kr.child_doors}
|
||||||
|
merge_sphere.free_locations = {**old_sphere.free_locations, **child_kr.free_locations}
|
||||||
|
merge_sphere.key_only_locations = {**old_sphere.key_only_locations, **child_kr.key_only_locations}
|
||||||
|
merge_sphere.bk_locked = old_sphere.bk_locked and child_kr.bk_locked
|
||||||
|
# this feels so ugly, key counters are much smarter than this - would love to get rid of spheres
|
||||||
return key_spheres
|
return key_spheres
|
||||||
|
|
||||||
|
|
||||||
@@ -519,9 +525,9 @@ def create_key_sphere(state, parent_sphere, door):
|
|||||||
parent_locations.update(p_region.key_only_locations)
|
parent_locations.update(p_region.key_only_locations)
|
||||||
parent_locations.update(p_region.other_locations)
|
parent_locations.update(p_region.other_locations)
|
||||||
p_region = p_region.parent_sphere
|
p_region = p_region.parent_sphere
|
||||||
u_doors = set(unique_doors(state.small_doors+state.big_doors)).difference(parent_doors)
|
u_doors = [x for x in unique_doors(state.small_doors+state.big_doors) if x not in parent_doors]
|
||||||
key_sphere.child_doors.update(dict.fromkeys(u_doors))
|
key_sphere.child_doors.update(dict.fromkeys(u_doors))
|
||||||
region_locations = list(set(state.found_locations).difference(parent_locations))
|
region_locations = [x for x in state.found_locations if x not in parent_locations]
|
||||||
for loc in region_locations:
|
for loc in region_locations:
|
||||||
if '- Prize' in loc.name or loc.name in ['Agahnim 1', 'Agahnim 2']:
|
if '- Prize' in loc.name or loc.name in ['Agahnim 1', 'Agahnim 2']:
|
||||||
key_sphere.prize_region = True
|
key_sphere.prize_region = True
|
||||||
@@ -712,7 +718,7 @@ def validate_key_layout_ex(key_layout, world, player):
|
|||||||
|
|
||||||
def validate_key_layout_main_loop(key_layout, world, player):
|
def validate_key_layout_main_loop(key_layout, world, player):
|
||||||
flat_proposal = key_layout.flat_prop
|
flat_proposal = key_layout.flat_prop
|
||||||
state = ExplorationState()
|
state = ExplorationState(dungeon=key_layout.sector.name)
|
||||||
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
||||||
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
@@ -765,7 +771,7 @@ def validate_key_layout_sub_loop(state, checked_states, flat_proposal, world, pl
|
|||||||
def create_key_counters(key_layout, world, player):
|
def create_key_counters(key_layout, world, player):
|
||||||
key_counters = {}
|
key_counters = {}
|
||||||
flat_proposal = key_layout.flat_prop
|
flat_proposal = key_layout.flat_prop
|
||||||
state = ExplorationState()
|
state = ExplorationState(dungeon=key_layout.sector.name)
|
||||||
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
|
||||||
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
|
||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
@@ -885,11 +891,11 @@ def validate_vanilla_key_logic(world, player):
|
|||||||
|
|
||||||
|
|
||||||
def val_hyrule(key_logic, world, player):
|
def val_hyrule(key_logic, world, player):
|
||||||
val_rule(key_logic.door_rules['Sewers Secret Room Key Door S'], 2)
|
val_rule(key_logic.door_rules['Sewers Secret Room Key Door S'], 3)
|
||||||
val_rule(key_logic.door_rules['Sewers Dark Cross Key Door N'], 2)
|
val_rule(key_logic.door_rules['Sewers Dark Cross Key Door N'], 3)
|
||||||
val_rule(key_logic.door_rules['Hyrule Dungeon Map Room Key Door S'], 2)
|
val_rule(key_logic.door_rules['Hyrule Dungeon Map Room Key Door S'], 2)
|
||||||
# why is allow_small actually false? - because chest key is forced elsewhere?
|
# why is allow_small actually false? - because chest key is forced elsewhere?
|
||||||
val_rule(key_logic.door_rules['Hyrule Dungeon Armory Interior Key Door N'], 4, True, 'Hyrule Castle - Zelda\'s Chest')
|
val_rule(key_logic.door_rules['Hyrule Dungeon Armory Interior Key Door N'], 3, True, 'Hyrule Castle - Zelda\'s Chest')
|
||||||
# val_rule(key_logic.door_rules['Hyrule Dungeon Armory Interior Key Door N'], 4)
|
# val_rule(key_logic.door_rules['Hyrule Dungeon Armory Interior Key Door N'], 4)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
9
Rules.py
9
Rules.py
@@ -363,6 +363,7 @@ def global_rules(world, player):
|
|||||||
set_rule(world.get_entrance('Ice Spike Room Up Stairs', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
set_rule(world.get_entrance('Ice Spike Room Up Stairs', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
||||||
set_rule(world.get_entrance('Ice Spike Room Down Stairs', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
set_rule(world.get_entrance('Ice Spike Room Down Stairs', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
||||||
set_rule(world.get_location('Ice Palace - Spike Room', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
set_rule(world.get_location('Ice Palace - Spike Room', player), lambda state: state.world.can_take_damage or state.has('Hookshot', player) or state.has('Cape', player) or state.has('Cane of Byrna', player))
|
||||||
|
set_rule(world.get_location('Ice Palace - Freezor Chest', player), lambda state: state.can_melt_things(player))
|
||||||
set_rule(world.get_entrance('Ice Hookshot Ledge Path', player), lambda state: state.has('Hookshot', player))
|
set_rule(world.get_entrance('Ice Hookshot Ledge Path', player), lambda state: state.has('Hookshot', player))
|
||||||
set_rule(world.get_entrance('Ice Hookshot Balcony Path', player), lambda state: state.has('Hookshot', player))
|
set_rule(world.get_entrance('Ice Hookshot Balcony Path', player), lambda state: state.has('Hookshot', player))
|
||||||
set_rule(world.get_entrance('Ice Switch Room SE', player), lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player))
|
set_rule(world.get_entrance('Ice Switch Room SE', player), lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player))
|
||||||
@@ -983,10 +984,12 @@ def open_rules(world, player):
|
|||||||
|
|
||||||
def swordless_rules(world, player):
|
def swordless_rules(world, player):
|
||||||
|
|
||||||
set_rule(world.get_entrance('Agahnim 1', player), lambda state: (state.has('Hammer', player) or state.has('Fire Rod', player) or state.can_shoot_arrows(player) or state.has('Cane of Somaria', player)) and state.has_key('Small Key (Agahnims Tower)', player, 2))
|
set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True)
|
||||||
|
set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True)
|
||||||
|
set_rule(world.get_entrance('Ice Lobby WS', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player))
|
||||||
|
set_rule(world.get_location('Ice Palace - Freezor Chest', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player))
|
||||||
|
|
||||||
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player))
|
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player))
|
||||||
set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player)) # no curtain
|
|
||||||
set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) #in swordless mode bombos pads are present in the relevant parts of ice palace
|
|
||||||
set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon, player))
|
set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon, player))
|
||||||
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop
|
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user