TR Crystal Maze adjustments
Fixed key door candidate finder to stay within own dungeon Standard mode support added Added missed Pre-moldorm chest Started work on new key logic analyzer
This commit is contained in:
@@ -12,6 +12,7 @@ from Dungeons import dungeon_regions, region_starts, split_region_starts, dungeo
|
||||
from Dungeons import drop_entrances
|
||||
from RoomData import DoorKind, PairedDoor
|
||||
from DungeonGenerator import ExplorationState, convert_regions, generate_dungeon
|
||||
from KeyDoorShuffle import analyze_dungeon
|
||||
|
||||
|
||||
def link_doors(world, player):
|
||||
@@ -124,6 +125,7 @@ def vanilla_key_logic(world, player):
|
||||
valid = validate_key_layout(key_layout, world, player)
|
||||
if not valid:
|
||||
raise Exception('Vanilla key layout not valid %s' % sector.name)
|
||||
analyze_dungeon(key_layout, world, player)
|
||||
if player not in world.key_logic.keys():
|
||||
world.key_logic[player] = {}
|
||||
world.key_logic[player][sector.name] = key_layout.key_logic
|
||||
@@ -288,11 +290,12 @@ def within_dungeon(world, player):
|
||||
for key, sector_list, entrance_list in dungeon_sectors:
|
||||
origin_list = list(entrance_list)
|
||||
find_enabled_origins(sector_list, enabled_entrances, origin_list)
|
||||
remove_drop_origins(origin_list)
|
||||
origin_list = remove_drop_origins(origin_list)
|
||||
ds = generate_dungeon(sector_list, origin_list, world, player)
|
||||
find_new_entrances(ds, connections, potentials, enabled_entrances)
|
||||
ds.name = key
|
||||
dungeon_layouts.append((ds, entrance_list))
|
||||
layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list
|
||||
dungeon_layouts.append((ds, layout_starts))
|
||||
|
||||
combine_layouts(dungeon_layouts, entrances_map)
|
||||
world.dungeon_layouts[player] = {}
|
||||
@@ -891,6 +894,7 @@ def flatten_pair_list(paired_list):
|
||||
|
||||
|
||||
def find_key_door_candidates(region, checked, world, player):
|
||||
dungeon = region.dungeon
|
||||
candidates = []
|
||||
checked_doors = list(checked)
|
||||
queue = collections.deque([(region, None, None)])
|
||||
@@ -920,7 +924,8 @@ def find_key_door_candidates(region, checked, world, player):
|
||||
valid = True
|
||||
if valid:
|
||||
candidates.append(d)
|
||||
queue.append((ext.connected_region, d, current)) # - todo: fix isolated ledge from re-entering
|
||||
if ext.connected_region.type != RegionType.Dungeon or ext.connected_region.dungeon == dungeon:
|
||||
queue.append((ext.connected_region, d, current))
|
||||
if d is not None:
|
||||
checked_doors.append(d)
|
||||
return candidates, checked_doors
|
||||
@@ -1206,7 +1211,8 @@ def determine_required_paths(world):
|
||||
paths['Turtle Rock'].insert(0, 'TR Lazy Eyes')
|
||||
if world.mode == 'standard':
|
||||
paths['Hyrule Castle'].append('Hyrule Dungeon Cellblock')
|
||||
paths['Hyrule Castle'].append('Sanctuary')
|
||||
# noinspection PyTypeChecker
|
||||
paths['Hyrule Castle'].append(('Hyrule Dungeon Cellblock', 'Sanctuary'))
|
||||
if world.doorShuffle in ['basic', 'experimental']:
|
||||
paths['Thieves Town'].append('Thieves Attic Window')
|
||||
return paths
|
||||
@@ -1235,6 +1241,9 @@ def find_inaccessible_regions(world, player):
|
||||
if connect is not None and connect.type is not RegionType.Dungeon and connect not in queue and connect not in visited_regions:
|
||||
queue.append(connect)
|
||||
world.inaccessible_regions.extend([r.name for r in all_regions.difference(visited_regions) if r.type is not RegionType.Cave])
|
||||
if world.mode == 'standard':
|
||||
world.inaccessible_regions.append('Hyrule Castle Ledge')
|
||||
world.inaccessible_regions.append('Sewer Drop')
|
||||
logger = logging.getLogger('')
|
||||
logger.info('Inaccessible Regions:')
|
||||
for r in world.inaccessible_regions:
|
||||
@@ -1462,6 +1471,9 @@ logical_connections = [
|
||||
('TR Pipe Ledge Drop Down', 'TR Pipe Pit'),
|
||||
('TR Big Chest Gap', 'TR Big Chest Entrance'),
|
||||
('TR Big Chest Entrance Gap', 'TR Big Chest'),
|
||||
('TR Crystal Maze Forwards Path', 'TR Crystal Maze End'),
|
||||
('TR Crystal Maze Blue Path', 'TR Crystal Maze'),
|
||||
('TR Crystal Maze Cane Path', 'TR Crystal Maze'),
|
||||
('GT Blocked Stairs Block Path', 'GT Big Chest'),
|
||||
('GT Hookshot East-North Path', 'GT Hookshot North Platform'),
|
||||
('GT Hookshot East-South Path', 'GT Hookshot South Platform'),
|
||||
|
||||
7
Doors.py
7
Doors.py
@@ -878,6 +878,9 @@ def create_doors(world, player):
|
||||
create_door(player, 'TR Dash Bridge WS', Nrml).dir(We, 0xc5, Bot, High).small_key().pos(0),
|
||||
create_door(player, 'TR Eye Bridge NW', Nrml).dir(No, 0xd5, Left, High).pos(1),
|
||||
create_door(player, 'TR Crystal Maze ES', Nrml).dir(Ea, 0xc4, Bot, High).small_key().pos(0),
|
||||
create_door(player, 'TR Crystal Maze Forwards Path', Lgcl),
|
||||
create_door(player, 'TR Crystal Maze Blue Path', Lgcl),
|
||||
create_door(player, 'TR Crystal Maze Cane Path', Lgcl),
|
||||
create_door(player, 'TR Crystal Maze North Stairs', StrS).dir(No, 0xc4, Mid, High),
|
||||
create_door(player, 'TR Final Abyss South Stairs', StrS).dir(No, 0xb4, Right, High),
|
||||
create_door(player, 'TR Final Abyss NW', Nrml).dir(No, 0xb4, Left, High).big_key().pos(0),
|
||||
@@ -1154,7 +1157,9 @@ def create_doors(world, player):
|
||||
world.get_door('TR Crystaroller SW', player).c_switch()
|
||||
world.get_door('TR Crystaroller Down Stairs', player).c_switch()
|
||||
world.get_door('TR Crystal Maze ES', player).c_switch()
|
||||
world.get_door('TR Crystal Maze North Stairs', player).c_switch()
|
||||
world.get_door('TR Crystal Maze Forwards Path', player).c_switch()
|
||||
world.get_door('TR Crystal Maze Cane Path', player).c_switch()
|
||||
world.get_door('TR Crystal Maze Blue Path', player).barrier(CrystalBarrier.Blue)
|
||||
|
||||
world.get_door('GT Crystal Conveyor NE', player).c_switch()
|
||||
world.get_door('GT Crystal Conveyor WN', player).c_switch()
|
||||
|
||||
@@ -41,8 +41,9 @@ def generate_dungeon(available_sectors, entrance_region_names, world, player):
|
||||
dungeon_cache = {}
|
||||
backtrack = False
|
||||
itr = 0
|
||||
finished = False
|
||||
# last_choice = None
|
||||
while len(proposed_map) < len(doors_to_connect):
|
||||
while not finished:
|
||||
# what are my choices?
|
||||
itr += 1
|
||||
if itr > 5000:
|
||||
@@ -55,6 +56,9 @@ def generate_dungeon(available_sectors, entrance_region_names, world, player):
|
||||
dungeon, hangers, hooks = dungeon_cache[depth]
|
||||
valid = True
|
||||
if valid:
|
||||
if len(proposed_map) == len(doors_to_connect):
|
||||
finished = True
|
||||
continue
|
||||
prev_choices = choices_master[depth]
|
||||
# make a choice
|
||||
hanger, hook = make_a_choice(dungeon, hangers, hooks, prev_choices)
|
||||
|
||||
@@ -274,7 +274,8 @@ tr_regions = [
|
||||
'TR Tile Room', 'TR Refill', 'TR Pokey 1', 'TR Chain Chomps', 'TR Pipe Pit', 'TR Pipe Ledge', 'TR Lava Dual Pipes',
|
||||
'TR Lava Island', 'TR Lava Escape', 'TR Pokey 2', 'TR Twin Pokeys', 'TR Hallway', 'TR Dodgers', 'TR Big View',
|
||||
'TR Big Chest', 'TR Big Chest Entrance', 'TR Lazy Eyes', 'TR Dash Room', 'TR Tongue Pull', 'TR Rupees',
|
||||
'TR Crystaroller', 'TR Dark Ride', 'TR Dash Bridge', 'TR Eye Bridge', 'TR Crystal Maze', 'TR Final Abyss', 'TR Boss'
|
||||
'TR Crystaroller', 'TR Dark Ride', 'TR Dash Bridge', 'TR Eye Bridge', 'TR Crystal Maze', 'TR Crystal Maze End',
|
||||
'TR Final Abyss', 'TR Boss'
|
||||
]
|
||||
|
||||
gt_regions = [
|
||||
|
||||
@@ -3138,7 +3138,7 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'),
|
||||
('Lumberjack House', 'Lumberjack House'),
|
||||
("Hyrule Castle Secret Entrance Drop", "Hyrule Castle Secret Entrance"),
|
||||
("Hyrule Castle Secret Entrance Stairs", "Hyrule Castle Secret Entrance"),
|
||||
("Hyrule Castle Secret Entrance Exit", "Light World"),
|
||||
("Hyrule Castle Secret Entrance Exit", "Hyrule Castle Courtyard"),
|
||||
('Bonk Fairy (Light)', 'Bonk Fairy (Light)'),
|
||||
('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'),
|
||||
('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'),
|
||||
@@ -3449,7 +3449,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Main L
|
||||
('Hyrule Castle Entrance (South)', 'Hyrule Castle Lobby'),
|
||||
('Hyrule Castle Entrance (West)', 'Hyrule Castle West Lobby'),
|
||||
('Hyrule Castle Entrance (East)', 'Hyrule Castle East Lobby'),
|
||||
('Hyrule Castle Exit (South)', 'Light World'),
|
||||
('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'),
|
||||
('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'),
|
||||
('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'),
|
||||
('Agahnims Tower', 'Tower Lobby'),
|
||||
|
||||
198
KeyDoorShuffle.py
Normal file
198
KeyDoorShuffle.py
Normal file
@@ -0,0 +1,198 @@
|
||||
import collections
|
||||
|
||||
from Regions import dungeon_events
|
||||
from DungeonGenerator import ExplorationState
|
||||
|
||||
|
||||
class KeyRegion(object):
|
||||
|
||||
def __init__(self):
|
||||
self.access_doors = set()
|
||||
self.free_locations = []
|
||||
self.prize_region = False
|
||||
self.key_only_locations = []
|
||||
self.child_doors = set()
|
||||
self.bk_locked = False
|
||||
self.parent_region = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if self.prize_region != other.prize_region:
|
||||
return False
|
||||
if self.bk_locked != other.bk_locked:
|
||||
return False
|
||||
if len(self.free_locations) != len(other.free_locations):
|
||||
return False
|
||||
if len(self.key_only_locations) != len(other.key_only_locations):
|
||||
return False
|
||||
if len(set(self.free_locations).difference(set(other.free_locations))) > 0:
|
||||
return False
|
||||
if len(set(self.key_only_locations).difference(set(other.key_only_locations))) > 0:
|
||||
return False
|
||||
if not self.check_child_dest(self.child_doors, other.child_doors, other.access_doors):
|
||||
return False
|
||||
if not self.check_child_dest(other.child_doors, self.child_doors, self.access_doors):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def check_child_dest(child_doors, other_child, other_access):
|
||||
for child in child_doors:
|
||||
if child in other_child:
|
||||
continue
|
||||
else:
|
||||
found = False
|
||||
for access in other_access:
|
||||
if access.dest == child:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
return False
|
||||
return True
|
||||
|
||||
# def issubset(self, other):
|
||||
# if self.prize_region != other.prize_region:
|
||||
# return False
|
||||
# if self.bk_locked != other.bk_locked:
|
||||
# return False
|
||||
# if not set(self.free_locations).issubset(set(other.free_locations)):
|
||||
# return False
|
||||
# if not set(self.key_only_locations).issubset(set(other.key_only_locations)):
|
||||
# return False
|
||||
# if not set(self.child_doors).issubset(set(other.child_doors)):
|
||||
# return False
|
||||
# return True
|
||||
#
|
||||
# def issuperset(self, other):
|
||||
# if self.prize_region != other.prize_region:
|
||||
# return False
|
||||
# if self.bk_locked != other.bk_locked:
|
||||
# return False
|
||||
# if not set(self.free_locations).issuperset(set(other.free_locations)):
|
||||
# return False
|
||||
# if not set(self.key_only_locations).issuperset(set(other.key_only_locations)):
|
||||
# return False
|
||||
# if not set(self.child_doors).issuperset(set(other.child_doors)):
|
||||
# return False
|
||||
# return True
|
||||
|
||||
|
||||
def analyze_dungeon(key_layout, world, player):
|
||||
flat_proposal = flatten_pair_list(key_layout.proposal)
|
||||
key_regions = create_key_regions(key_layout, flat_proposal, world, player)
|
||||
start = key_regions['Origin']
|
||||
|
||||
|
||||
def create_key_regions(key_layout, flat_proposal, world, player):
|
||||
key_regions = {}
|
||||
state = ExplorationState()
|
||||
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
|
||||
for region in key_layout.start_regions:
|
||||
state.visit_region(region, key_checks=True)
|
||||
state.add_all_doors_check_keys(region, flat_proposal, world, player)
|
||||
expand_key_state(state, flat_proposal, world, player)
|
||||
key_regions['Origin'] = create_key_region(state, None, None)
|
||||
queue = collections.deque([(key_regions['Origin'], state)])
|
||||
while len(queue) > 0:
|
||||
next_key_region, parent_state = queue.popleft()
|
||||
for door in next_key_region.child_doors:
|
||||
child_state = parent_state.copy()
|
||||
# open the door
|
||||
open_a_door(door, child_state, flat_proposal)
|
||||
expand_key_state(child_state, flat_proposal, world, player)
|
||||
child_kr = create_key_region(child_state, next_key_region, door)
|
||||
check_for_duplicates_sub_super_set(key_regions, child_kr, door.name)
|
||||
queue.append((child_kr, child_state))
|
||||
return key_regions
|
||||
|
||||
|
||||
def check_for_duplicates_sub_super_set(key_regions, new_kr, door_name):
|
||||
is_new = True
|
||||
for kr in key_regions.values():
|
||||
if new_kr == kr:
|
||||
kr.access_doors.update(new_kr.access_doors)
|
||||
kr.child_doors.update(new_kr.child_doors)
|
||||
key_regions[door_name] = kr
|
||||
is_new = False
|
||||
break
|
||||
# if new_kr.issubset(kr):
|
||||
# break
|
||||
# if new_kr.issuperset(kr):
|
||||
# break
|
||||
if is_new:
|
||||
key_regions[door_name] = new_kr
|
||||
|
||||
|
||||
def create_key_region(state, parent_region, door):
|
||||
key_region = KeyRegion()
|
||||
key_region.parent_region = parent_region
|
||||
p_region = parent_region
|
||||
parent_doors = set()
|
||||
parent_locations = set()
|
||||
while p_region is not None:
|
||||
parent_doors.update(p_region.child_doors)
|
||||
parent_locations.update(p_region.free_locations+p_region.key_only_locations)
|
||||
p_region = p_region.parent_region
|
||||
u_doors = unique_doors(state.small_doors+state.big_doors).difference(parent_doors)
|
||||
key_region.child_doors.update(u_doors)
|
||||
region_locations = set(state.found_locations).difference(parent_locations)
|
||||
for loc in region_locations:
|
||||
if '- Prize' in loc.name or loc.name in ['Agahnim 1', 'Agahnim 2']:
|
||||
key_region.prize_region = True
|
||||
elif loc.event and 'Small Key' in loc.item.name:
|
||||
key_region.key_only_locations.append(loc)
|
||||
elif loc.name not in dungeon_events:
|
||||
key_region.free_locations.append(loc)
|
||||
key_region.bk_locked = state.big_key_opened
|
||||
if door is not None:
|
||||
key_region.access_doors.add(door)
|
||||
return key_region
|
||||
|
||||
|
||||
def open_a_door(door, child_state, flat_proposal):
|
||||
if door.bigKey:
|
||||
child_state.big_key_opened = True
|
||||
child_state.avail_doors.extend(child_state.big_doors)
|
||||
child_state.opened_doors.extend(set([d.door for d in child_state.big_doors]))
|
||||
child_state.big_doors.clear()
|
||||
else:
|
||||
child_state.opened_doors.append(door)
|
||||
doors_to_open = [x for x in child_state.small_doors if x.door == door]
|
||||
child_state.small_doors[:] = [x for x in child_state.small_doors if x.door != door]
|
||||
child_state.avail_doors.extend(doors_to_open)
|
||||
dest_door = door.dest
|
||||
if dest_door in flat_proposal:
|
||||
child_state.opened_doors.append(dest_door)
|
||||
if child_state.in_door_list_ic(dest_door, child_state.small_doors):
|
||||
now_available = [x for x in child_state.small_doors if x.door == dest_door]
|
||||
child_state.small_doors[:] = [x for x in child_state.small_doors if x.door != dest_door]
|
||||
child_state.avail_doors.extend(now_available)
|
||||
|
||||
|
||||
def unique_doors(doors):
|
||||
unique_d_set = set()
|
||||
for d in doors:
|
||||
if d.door not in unique_d_set:
|
||||
unique_d_set.add(d.door)
|
||||
return unique_d_set
|
||||
|
||||
|
||||
def expand_key_state(state, flat_proposal, world, player):
|
||||
while len(state.avail_doors) > 0:
|
||||
exp_door = state.next_avail_door()
|
||||
door = exp_door.door
|
||||
connect_region = world.get_entrance(door.name, player).connected_region
|
||||
if state.validate(door, connect_region, world):
|
||||
state.visit_region(connect_region, key_checks=True)
|
||||
state.add_all_doors_check_keys(connect_region, flat_proposal, world, player)
|
||||
|
||||
|
||||
def flatten_pair_list(paired_list):
|
||||
flat_list = []
|
||||
for d in paired_list:
|
||||
if type(d) is tuple:
|
||||
flat_list.append(d[0])
|
||||
flat_list.append(d[1])
|
||||
else:
|
||||
flat_list.append(d)
|
||||
return flat_list
|
||||
@@ -611,7 +611,8 @@ def create_regions(world, player):
|
||||
create_dungeon_region(player, 'TR Eye Bridge', 'Turtle Rock', ['Turtle Rock - Eye Bridge - Bottom Left', 'Turtle Rock - Eye Bridge - Bottom Right',
|
||||
'Turtle Rock - Eye Bridge - Top Left', 'Turtle Rock - Eye Bridge - Top Right'],
|
||||
['Turtle Rock Isolated Ledge Exit', 'TR Eye Bridge NW']),
|
||||
create_dungeon_region(player, 'TR Crystal Maze', 'Turtle Rock', None, ['TR Crystal Maze ES', 'TR Crystal Maze North Stairs']),
|
||||
create_dungeon_region(player, 'TR Crystal Maze', 'Turtle Rock', None, ['TR Crystal Maze ES', 'TR Crystal Maze Forwards Path']),
|
||||
create_dungeon_region(player, 'TR Crystal Maze End', 'Turtle Rock', None, ['TR Crystal Maze Blue Path', 'TR Crystal Maze Cane Path', 'TR Crystal Maze North Stairs']),
|
||||
create_dungeon_region(player, 'TR Final Abyss', 'Turtle Rock', None, ['TR Final Abyss South Stairs', 'TR Final Abyss NW']),
|
||||
create_dungeon_region(player, 'TR Boss', 'Turtle Rock', ['Turtle Rock - Boss', 'Turtle Rock - Prize'], ['TR Boss SW']),
|
||||
|
||||
@@ -692,7 +693,7 @@ def create_regions(world, player):
|
||||
create_dungeon_region(player, 'GT Mini Helmasaur Room', 'Ganon\'s Tower', ['Ganons Tower - Mini Helmasaur Room - Left',
|
||||
'Ganons Tower - Mini Helmasaur Room - Right', 'Ganons Tower - Mini Helmasuar Key Drop'], ['GT Mini Helmasaur Room SE', 'GT Mini Helmasaur Room WN']),
|
||||
create_dungeon_region(player, 'GT Bomb Conveyor', 'Ganon\'s Tower', None, ['GT Bomb Conveyor EN', 'GT Bomb Conveyor SW']),
|
||||
create_dungeon_region(player, 'GT Crystal Circles', 'Ganon\'s Tower', None, ['GT Crystal Circles NW', 'GT Crystal Circles SW']),
|
||||
create_dungeon_region(player, 'GT Crystal Circles', 'Ganon\'s Tower', ['Ganons Tower - Pre-Moldorm Chest'], ['GT Crystal Circles NW', 'GT Crystal Circles SW']),
|
||||
create_dungeon_region(player, 'GT Left Moldorm Ledge', 'Ganon\'s Tower', None, ['GT Left Moldorm Ledge Drop Down', 'GT Left Moldorm Ledge NW']),
|
||||
create_dungeon_region(player, 'GT Right Moldorm Ledge', 'Ganon\'s Tower', None, ['GT Right Moldorm Ledge Down Stairs', 'GT Right Moldorm Ledge Drop Down']),
|
||||
create_dungeon_region(player, 'GT Moldorm', 'Ganon\'s Tower', None, ['GT Moldorm Hole', 'GT Moldorm Gap']),
|
||||
|
||||
6
Rules.py
6
Rules.py
@@ -420,6 +420,7 @@ def global_rules(world, player):
|
||||
set_rule(world.get_entrance('TR Dodgers NE', player), lambda state: state.has('Big Key (Turtle Rock)', player))
|
||||
set_rule(world.get_entrance('TR Dark Ride Up Stairs', player), lambda state: state.has('Cane of Somaria', player))
|
||||
set_rule(world.get_entrance('TR Dark Ride SW', player), lambda state: state.has('Cane of Somaria', player))
|
||||
set_rule(world.get_entrance('TR Crystal Maze Cane Path', player), lambda state: state.has('Cane of Somaria', player))
|
||||
set_rule(world.get_entrance('TR Final Abyss South Stairs', player), lambda state: state.has('Cane of Somaria', player))
|
||||
set_rule(world.get_entrance('TR Final Abyss NW', player), lambda state: state.has('Cane of Somaria', player) and state.has('Big Key (Turtle Rock)', player))
|
||||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player), lambda state: state.has('Cane of Byrna', player) or state.has('Cape', player) or state.has('Mirror Shield', player))
|
||||
@@ -1046,7 +1047,10 @@ def standard_rules(world, player):
|
||||
set_rule(world.get_location('Hyrule Castle - Boomerang Chest', player), lambda state: state.can_kill_most_things(player))
|
||||
set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest', player), lambda state: state.can_kill_most_things(player))
|
||||
|
||||
|
||||
set_rule(world.get_location('Hyrule Castle - Map Guard Key Drop', player), lambda state: state.can_kill_most_things(player))
|
||||
set_rule(world.get_location('Hyrule Castle - Boomerang Guard Key Drop', player), lambda state: state.can_kill_most_things(player))
|
||||
set_rule(world.get_location('Hyrule Castle - Key Rat Key Drop', player), lambda state: state.can_kill_most_things(player))
|
||||
set_rule(world.get_entrance('Hyrule Dungeon Armory S', player), lambda state: state.can_kill_most_things(player))
|
||||
|
||||
|
||||
def set_trock_key_rules(world, player):
|
||||
|
||||
Reference in New Issue
Block a user