Merging of CrossDungeon into DoorDev

This commit is contained in:
aerinon
2020-01-02 11:42:40 -07:00
9 changed files with 85 additions and 38 deletions

View File

@@ -1150,9 +1150,9 @@ def find_inaccessible_regions(world, player):
world.inaccessible_regions[player].append('Hyrule Castle Ledge')
world.inaccessible_regions[player].append('Sewer Drop')
logger = logging.getLogger('')
logger.info('Inaccessible Regions:')
logger.debug('Inaccessible Regions:')
for r in world.inaccessible_regions[player]:
logger.info('%s', r)
logger.debug('%s', r)
def valid_inaccessible_region(r):
@@ -1661,10 +1661,10 @@ interior_doors = [
('Skull Big Key WN', 'Skull Lone Pot EN'),
('Skull Small Hall WS', 'Skull 2 West Lobby ES'),
('Skull 2 West Lobby NW', 'Skull X Room SW'),
('Skull 3 Lobby WN', 'Skull East Bridge EN'),
('Skull East Bridge ES', 'Skull West Bridge Nook WS'),
('Skull Star Pits WS', 'Skull Torch Room ES'),
('Skull Torch Room EN', 'Skull Vines WN'),
('Skull 3 Lobby EN', 'Skull East Bridge WN'),
('Skull East Bridge WS', 'Skull West Bridge Nook ES'),
('Skull Star Pits ES', 'Skull Torch Room WS'),
('Skull Torch Room WN', 'Skull Vines EN'),
('Skull Spike Corner ES', 'Skull Final Drop WS'),
('Thieves Hallway WS', 'Thieves Pot Alcove Mid ES'),
('Thieves Conveyor Maze SW', 'Thieves Pot Alcove Top NW'),

View File

@@ -307,9 +307,9 @@ def create_doors(world, player):
create_door(player, 'PoD Lobby N', Intr).dir(No, 0x4a, Mid, High).pos(3),
create_door(player, 'PoD Lobby NW', Intr).dir(No, 0x4a, Left, High).pos(0),
create_door(player, 'PoD Lobby NE', Intr).dir(No, 0x4a, Right, High).pos(1),
create_door(player, 'PoD Left Cage SW', Intr).dir(No, 0x4a, Left, High).pos(0),
create_door(player, 'PoD Middle Cage S', Intr).dir(No, 0x4a, Mid, High).pos(3),
create_door(player, 'PoD Middle Cage SE', Intr).dir(No, 0x4a, Right, High).pos(1),
create_door(player, 'PoD Left Cage SW', Intr).dir(So, 0x4a, Left, High).pos(0),
create_door(player, 'PoD Middle Cage S', Intr).dir(So, 0x4a, Mid, High).pos(3),
create_door(player, 'PoD Middle Cage SE', Intr).dir(So, 0x4a, Right, High).pos(1),
create_door(player, 'PoD Left Cage Down Stairs', Sprl).dir(Dn, 0x4a, 1, HTH).ss(A, 0x12, 0x80, False, True),
create_door(player, 'PoD Middle Cage Down Stairs', Sprl).dir(Dn, 0x4a, 0, HTH).ss(S, 0x12, 0x80, False, True),
create_door(player, 'PoD Middle Cage N', Nrml).dir(No, 0x4a, Mid, High).small_key().pos(2),
@@ -358,7 +358,7 @@ def create_doors(world, player):
create_door(player, 'PoD Dark Maze EN', Nrml).dir(Ea, 0x19, Top, High).small_key().pos(1),
create_door(player, 'PoD Dark Maze E', Nrml).dir(Ea, 0x19, Mid, High).pos(0),
create_door(player, 'PoD Compass Room WN', Intr).dir(We, 0x1a, Top, High).pos(4),
create_door(player, 'PoD Compass Room SE', Intr).dir(No, 0x1a, Mid, High).small_key().pos(0),
create_door(player, 'PoD Compass Room SE', Intr).dir(So, 0x1a, Mid, High).small_key().pos(0),
create_door(player, 'PoD Harmless Hellway NE', Intr).dir(No, 0x1a, Right, High).small_key().pos(0),
create_door(player, 'PoD Harmless Hellway SE', Nrml).dir(So, 0x1a, Right, High).pos(5),
create_door(player, 'PoD Compass Room W Down Stairs', Sprl).dir(Dn, 0x1a, 0, HTH).ss(S, 0x12, 0x50, True, True),
@@ -466,7 +466,7 @@ def create_doors(world, player):
create_door(player, 'Swamp Flooded Spot Ladder', Lgcl),
create_door(player, 'Swamp Flooded Room Ladder', Lgcl),
create_door(player, 'Swamp Basement Shallows NW', Nrml).dir(No, 0x76, Left, High).toggler().pos(2),
create_door(player, 'Swamp Basement Shallows EN', Intr).dir(We, 0x76, Top, High).pos(0),
create_door(player, 'Swamp Basement Shallows EN', Intr).dir(Ea, 0x76, Top, High).pos(0),
create_door(player, 'Swamp Basement Shallows ES', Intr).dir(Ea, 0x76, Bot, High).pos(1),
create_door(player, 'Swamp Waterfall Room SW', Nrml).dir(So, 0x66, Left, Low).toggler().pos(1),
create_door(player, 'Swamp Waterfall Room NW', Intr).dir(No, 0x66, Left, Low).pos(3),
@@ -514,15 +514,15 @@ def create_doors(world, player):
create_door(player, 'Skull X Room SW', Intr).dir(So, 0x56, Left, High).small_key().pos(0),
create_door(player, 'Skull Back Drop Star Path', Lgcl),
create_door(player, 'Skull 3 Lobby NW', Nrml).dir(No, 0x59, Left, High).small_key().pos(0),
create_door(player, 'Skull 3 Lobby WN', Intr).dir(We, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge EN', Intr).dir(Ea, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge ES', Intr).dir(Ea, 0x59, Bot, High).pos(3),
create_door(player, 'Skull West Bridge Nook WS', Intr).dir(We, 0x59, Bot, High).pos(3),
create_door(player, 'Skull 3 Lobby EN', Intr).dir(Ea, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge WN', Intr).dir(We, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge WS', Intr).dir(We, 0x59, Bot, High).pos(3),
create_door(player, 'Skull West Bridge Nook ES', Intr).dir(Ea, 0x59, Bot, High).pos(3),
create_door(player, 'Skull Star Pits SW', Nrml).dir(So, 0x49, Left, High).small_key().pos(2),
create_door(player, 'Skull Star Pits WS', Intr).dir(We, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room ES', Intr).dir(Ea, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room EN', Intr).dir(Ea, 0x49, Top, High).pos(1),
create_door(player, 'Skull Vines WN', Intr).dir(We, 0x49, Top, High).pos(1),
create_door(player, 'Skull Star Pits ES', Intr).dir(Ea, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room WS', Intr).dir(We, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room WN', Intr).dir(We, 0x49, Top, High).pos(1),
create_door(player, 'Skull Vines EN', Intr).dir(Ea, 0x49, Top, High).pos(1),
create_door(player, 'Skull Vines NW', Nrml).dir(No, 0x49, Left, High).pos(0),
create_door(player, 'Skull Spike Corner SW', Nrml).dir(So, 0x39, Left, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Skull Spike Corner ES', Intr).dir(Ea, 0x39, Bot, High).small_key().pos(1),
@@ -701,7 +701,7 @@ def create_doors(world, player):
create_door(player, 'Mire Lobby Gap', Lgcl),
create_door(player, 'Mire Post-Gap Gap', Lgcl),
create_door(player, 'Mire Post-Gap Down Stairs', Sprl).dir(Up, 0x98, 0, HTH).ss(X, 0x11, 0x90, False, True),
create_door(player, 'Mire Post-Gap Down Stairs', Sprl).dir(Dn, 0x98, 0, HTH).ss(X, 0x11, 0x90, False, True),
create_door(player, 'Mire 2 Up Stairs', Sprl).dir(Up, 0xd2, 0, HTH).ss(X, 0x1a, 0x7c, False, True),
create_door(player, 'Mire 2 NE', Nrml).dir(No, 0xd2, Right, High).trap(0x4).pos(0),
create_door(player, 'Mire Hub SE', Nrml).dir(So, 0xc2, Right, High).pos(5),

View File

@@ -1482,7 +1482,7 @@ def valid_polarized_assignment(builder, sector_list):
sector_mag = sector.magnitude()
for i in range(len(sector_mag)):
if sector_mag[i] > 0 and other_mag[i] == 0:
return True
return False
# dead_ends = 0
# branches = 0
# for sector in sector_list:

View File

@@ -8,6 +8,7 @@ import sys
from Main import main
from Utils import is_bundled, close_console, output_path
from Fill import FillError
class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
@@ -303,11 +304,22 @@ def start():
guiMain(args)
elif args.count is not None:
seed = args.seed
failures = []
logger = logging.getLogger('')
for _ in range(args.count):
main(seed=seed, args=args)
try:
main(seed=seed, args=args)
logger.info('Finished run %s', _+1)
except (FillError, Exception, RuntimeError) as err:
failures.append((err, seed))
logger.warning('Generation failed: %s', err)
seed = random.randint(0, 999999999)
for fail in failures:
logger.info('%s seed failed with: %s', fail[1], fail[0])
logger.info('Generation fail rate: %f%%', 100*len(failures)/args.count)
else:
main(seed=args.seed, args=args)
if __name__ == '__main__':
start()

10
Fill.py
View File

@@ -190,9 +190,17 @@ def fill_restrictive(world, base_state, locations, itempool):
for item_to_place in items_to_place:
spot_to_fill = None
for location in locations:
if location.can_fill(maximum_exploration_state, item_to_place, perform_access_check):
if item_to_place.key: # a better test to see if a key can go there
location.item = item_to_place
test_state = maximum_exploration_state.copy()
test_state.stale[item_to_place.player] = True
else:
test_state = maximum_exploration_state
if location.can_fill(test_state, item_to_place, perform_access_check):
spot_to_fill = location
break
elif item_to_place.key:
location.item = None
if spot_to_fill is None:
# we filled all reachable spots. Maybe the game can be beaten anyway?

View File

@@ -118,8 +118,9 @@ def analyze_dungeon(key_layout, world, player):
raw_avail = chest_keys + len(key_counter.key_only_locations)
available = raw_avail - key_counter.used_keys
possible_smalls = count_unique_small_doors(key_counter, key_layout.flat_prop)
avail_bigs = count_unique_big_doors(key_counter)
if not key_counter.big_key_opened:
if chest_keys == count_locations_big_optional(key_counter.free_locations) and available <= possible_smalls:
if chest_keys == count_locations_big_optional(key_counter.free_locations) and available <= possible_smalls and avail_bigs == 0:
key_logic.bk_restricted.update(filter_big_chest(key_counter.free_locations))
if not key_counter.big_key_opened and big_chest_in_locations(key_counter.free_locations):
key_logic.sm_restricted.update(find_big_chest_locations(key_counter.free_locations))
@@ -161,6 +162,13 @@ def queue_sorter(queue_item):
return 1 if door.bigKey else 0
def queue_sorter_2(queue_item):
door, counter, key_only = queue_item
if door is None:
return 0
return 1 if door.bigKey else 0
def find_bk_locked_sections(key_layout, world):
key_counters = key_layout.key_counters
key_logic = key_layout.key_logic
@@ -479,6 +487,17 @@ def count_unique_small_doors(key_counter, proposal):
return cnt
def count_unique_big_doors(key_counter):
cnt = 0
counted = set()
for door in key_counter.child_doors:
if door.bigKey and door not in counted:
cnt += 1
counted.add(door)
counted.add(door.dest)
return cnt
def count_locations_big_optional(locations, bk=False):
cnt = 0
for loc in locations:
@@ -535,13 +554,13 @@ def flatten_pair_list(paired_list):
def check_rules(original_counter, key_layout):
all_key_only = set()
key_only_map = {}
queue = collections.deque([(None, original_counter)])
queue = collections.deque([(None, original_counter, original_counter.key_only_locations)])
completed = set()
completed.add(cid(original_counter, key_layout))
while len(queue) > 0:
queue = collections.deque(sorted(queue, key=queue_sorter))
access_door, counter = queue.popleft()
for loc in counter.key_only_locations:
queue = collections.deque(sorted(queue, key=queue_sorter_2))
access_door, counter, key_only_loc = queue.popleft()
for loc in key_only_loc:
if loc not in all_key_only:
all_key_only.add(loc)
access_rules = []
@@ -549,16 +568,20 @@ def check_rules(original_counter, key_layout):
else:
access_rules = key_only_map[loc]
if access_door is None or access_door.name not in key_layout.key_logic.door_rules.keys():
access_rules.append(DoorRules(0))
if access_door is None or not access_door.bigKey:
access_rules.append(DoorRules(0))
else:
access_rules.append(key_layout.key_logic.door_rules[access_door.name])
rule = key_layout.key_logic.door_rules[access_door.name]
if rule not in access_rules:
access_rules.append(rule)
for child in counter.child_doors.keys():
if not child.bigKey or not key_layout.big_key_special or counter.big_key_opened:
next_counter = find_next_counter(child, counter, key_layout)
c_id = cid(next_counter, key_layout)
if c_id not in completed:
completed.add(c_id)
queue.append((child, next_counter))
new_key_only = dict_difference(next_counter.key_only_locations, counter.key_only_locations)
queue.append((child, next_counter, new_key_only))
min_rule_bk = defaultdict(list)
min_rule_non_bk = defaultdict(list)
check_non_bk = False

View File

@@ -432,12 +432,12 @@ def create_regions(world, player):
create_dungeon_region(player, 'Skull Back Drop', 'Skull Woods', None, ['Skull Back Drop Star Path', ]),
create_dungeon_region(player, 'Skull 2 West Lobby', 'Skull Woods', ['Skull Woods - West Lobby Pot Key'], ['Skull 2 West Lobby ES', 'Skull 2 West Lobby NW', 'Skull Woods Second Section Exit (West)']),
create_dungeon_region(player, 'Skull X Room', 'Skull Woods', None, ['Skull X Room SW']),
create_dungeon_region(player, 'Skull 3 Lobby', 'Skull Woods', None, ['Skull 3 Lobby NW', 'Skull 3 Lobby WN', 'Skull Woods Final Section Exit']),
create_dungeon_region(player, 'Skull East Bridge', 'Skull Woods', None, ['Skull East Bridge EN', 'Skull East Bridge ES']),
create_dungeon_region(player, 'Skull West Bridge Nook', 'Skull Woods', ['Skull Woods - Bridge Room'], ['Skull West Bridge Nook WS']),
create_dungeon_region(player, 'Skull Star Pits', 'Skull Woods', None, ['Skull Star Pits SW', 'Skull Star Pits WS']),
create_dungeon_region(player, 'Skull Torch Room', 'Skull Woods', None, ['Skull Torch Room ES', 'Skull Torch Room EN']),
create_dungeon_region(player, 'Skull Vines', 'Skull Woods', None, ['Skull Vines WN', 'Skull Vines NW']),
create_dungeon_region(player, 'Skull 3 Lobby', 'Skull Woods', None, ['Skull 3 Lobby NW', 'Skull 3 Lobby EN', 'Skull Woods Final Section Exit']),
create_dungeon_region(player, 'Skull East Bridge', 'Skull Woods', None, ['Skull East Bridge WN', 'Skull East Bridge WS']),
create_dungeon_region(player, 'Skull West Bridge Nook', 'Skull Woods', ['Skull Woods - Bridge Room'], ['Skull West Bridge Nook ES']),
create_dungeon_region(player, 'Skull Star Pits', 'Skull Woods', None, ['Skull Star Pits SW', 'Skull Star Pits ES']),
create_dungeon_region(player, 'Skull Torch Room', 'Skull Woods', None, ['Skull Torch Room WS', 'Skull Torch Room WN']),
create_dungeon_region(player, 'Skull Vines', 'Skull Woods', None, ['Skull Vines EN', 'Skull Vines NW']),
create_dungeon_region(player, 'Skull Spike Corner', 'Skull Woods', ['Skull Woods - Spike Corner Key Drop'], ['Skull Spike Corner SW', 'Skull Spike Corner ES']),
create_dungeon_region(player, 'Skull Final Drop', 'Skull Woods', None, ['Skull Final Drop WS', 'Skull Final Drop Hole']),
create_dungeon_region(player, 'Skull Boss', 'Skull Woods', ['Skull Woods - Boss', 'Skull Woods - Prize']),

4
Rom.py
View File

@@ -534,6 +534,10 @@ def patch_rom(world, player, rom):
patch_shuffled_dark_sanc(world, rom, player)
# patch doors
if world.doorShuffle == 'crossed':
rom.write_byte(0x151f1, 2)
rom.write_byte(0x15270, 2)
rom.write_byte(0x1597b, 2)
for door in world.doors:
if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs]:
rom.write_bytes(door.getAddress(), door.dest.getTarget(door.toggle))

View File

@@ -324,7 +324,7 @@ def global_rules(world, player):
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Prize', player))
set_rule(world.get_entrance('Skull Big Chest Hookpath', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Skull Torch Room EN', player), lambda state: state.has('Fire Rod', player))
set_rule(world.get_entrance('Skull Torch Room WN', player), lambda state: state.has('Fire Rod', player))
set_rule(world.get_entrance('Skull Vines NW', player), lambda state: state.has_sword(player))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))