diff --git a/BaseClasses.py b/BaseClasses.py index 09e6a1fe..c25e083c 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -16,7 +16,7 @@ class World(object): def __init__(self, players, shuffle, doorShuffle, logic, mode, swords, difficulty, difficulty_adjustments, timer, progressive, goal, algorithm, accessibility, shuffle_ganon, retro, custom, customitemarray, hints): self.players = players self.shuffle = shuffle.copy() - self.doorShuffle = doorShuffle + self.doorShuffle = doorShuffle.copy() self.logic = logic.copy() self.mode = mode.copy() self.swords = swords.copy() @@ -1510,6 +1510,7 @@ class Spoiler(object): 'weapons': self.world.swords, 'goal': self.world.goal, 'shuffle': self.world.shuffle, + 'door_shuffle': self.world.doorShuffle, 'item_pool': self.world.difficulty, 'item_functionality': self.world.difficulty_adjustments, 'gt_crystals': self.world.crystals_needed_for_gt, @@ -1560,6 +1561,7 @@ class Spoiler(object): outfile.write('Difficulty: %s\n' % self.metadata['item_pool']) outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality']) outfile.write('Entrance Shuffle: %s\n' % self.metadata['shuffle']) + outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle']) outfile.write('Crystals required for GT: %s\n' % self.metadata['gt_crystals']) outfile.write('Crystals required for Ganon: %s\n' % self.metadata['ganon_crystals']) outfile.write('Pyramid hole pre-opened: %s\n' % {k: 'Yes' if v else 'No' for k, v in self.metadata['open_pyramid'].items()}) diff --git a/DoorShuffle.py b/DoorShuffle.py index c8ed3263..0e70d22b 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -39,7 +39,7 @@ def link_doors(world, player): for ent, ext in ladders: connect_two_way(world, ent, ext, player) - if world.doorShuffle == 'vanilla': + if world.doorShuffle[player] == 'vanilla': for exitName, regionName in vanilla_logical_connections: connect_simple_door(world, exitName, regionName, player) for entrance, ext in spiral_staircases: @@ -49,14 +49,14 @@ def link_doors(world, player): for ent, ext in default_one_way_connections: connect_one_way(world, ent, ext, player) vanilla_key_logic(world, player) - elif world.doorShuffle == 'basic': + elif world.doorShuffle[player] == 'basic': within_dungeon(world, player) - elif world.doorShuffle == 'crossed': + elif world.doorShuffle[player] == 'crossed': cross_dungeon(world, player) - elif world.doorShuffle == 'experimental': + elif world.doorShuffle[player] == 'experimental': experiment(world, player) - if world.doorShuffle != 'vanilla': + if world.doorShuffle[player] != 'vanilla': create_door_spoiler(world, player) @@ -83,7 +83,7 @@ def mark_regions(world, player): def create_door_spoiler(world, player): logger = logging.getLogger('') - queue = collections.deque(world.doors) + queue = collections.deque((door for door in world.doors if door.player == player)) while len(queue) > 0: door_a = queue.popleft() if door_a.type in [DoorType.Normal, DoorType.SpiralStairs]: @@ -283,7 +283,7 @@ def within_dungeon(world, player): handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map) main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player) - paths = determine_required_paths(world) + paths = determine_required_paths(world, player) check_required_paths(paths, world, player) # shuffle_key_doors for dungeons @@ -637,7 +637,7 @@ def cross_dungeon(world, player): main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player) - paths = determine_required_paths(world) + paths = determine_required_paths(world, player) check_required_paths(paths, world, player) start = time.process_time() @@ -1097,7 +1097,7 @@ def change_door_to_small_key(d, world, player): room.change(d.doorListPos, DoorKind.SmallKey) -def determine_required_paths(world): +def determine_required_paths(world, player): paths = { 'Hyrule Castle': [], 'Eastern Palace': ['Eastern Boss'], @@ -1122,7 +1122,7 @@ def determine_required_paths(world): paths['Hyrule Castle'].append('Hyrule Dungeon Cellblock') # noinspection PyTypeChecker paths['Hyrule Castle'].append(('Hyrule Dungeon Cellblock', 'Sanctuary')) - if world.doorShuffle in ['basic', 'experimental']: # todo: crossed? + if world.doorShuffle[player] in ['basic', 'experimental']: # todo: crossed? paths['Thieves Town'].append('Thieves Attic Window') return paths diff --git a/DungeonRandomizer.py b/DungeonRandomizer.py index 9df11af2..0178233e 100755 --- a/DungeonRandomizer.py +++ b/DungeonRandomizer.py @@ -298,7 +298,7 @@ def parse_arguments(argv, no_defaults=False): playerargs = parse_arguments(shlex.split(getattr(ret,f"p{player}")), True) for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', - 'shuffle', 'crystals_ganon', 'crystals_gt', 'openpyramid', + 'shuffle', 'door_shuffle', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', 'retro', 'accessibility', 'hints', 'beemizer', 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 86da7b2a..f0ac0096 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -95,7 +95,7 @@ def build_key_layout(builder, start_regions, proposal, world, player): def calc_max_chests(builder, key_layout, world, player): - if world.doorShuffle != 'crossed': + if world.doorShuffle[player] != 'crossed': return len(world.get_dungeon(key_layout.sector.name, player).small_keys) return builder.key_doors_num - key_layout.max_drops @@ -129,7 +129,7 @@ def analyze_dungeon(key_layout, world, player): child_queue = collections.deque() for child in key_counter.child_doors.keys(): if not child.bigKey or not key_layout.big_key_special or key_counter.big_key_opened: - odd_counter = create_odd_key_counter(child, key_counter, key_layout, world) + odd_counter = create_odd_key_counter(child, key_counter, key_layout, world, player) if not empty_counter(odd_counter) and child not in doors_completed: child_queue.append((child, odd_counter)) while len(child_queue) > 0: @@ -137,7 +137,7 @@ def analyze_dungeon(key_layout, world, player): if not child.bigKey: best_counter = find_best_counter(child, odd_counter, key_counter, key_layout, world, player, False) rule = create_rule(best_counter, key_counter, key_layout, world, player) - check_for_self_lock_key(rule, child, best_counter, key_layout, world) + check_for_self_lock_key(rule, child, best_counter, key_layout, world, player) bk_restricted_rules(rule, child, odd_counter, key_counter, key_layout, world, player) key_logic.door_rules[child.name] = rule doors_completed.add(child) @@ -330,9 +330,9 @@ def create_rule(key_counter, prev_counter, key_layout, world, player): return DoorRules(rule_num) -def check_for_self_lock_key(rule, door, parent_counter, key_layout, world): +def check_for_self_lock_key(rule, door, parent_counter, key_layout, world, player): if world.accessibility != 'locations': - counter = find_inverted_counter(door, parent_counter, key_layout, world) + counter = find_inverted_counter(door, parent_counter, key_layout, world, player) if not self_lock_possible(counter): return if len(counter.free_locations) == 1 and len(counter.key_only_locations) == 0 and not counter.important_location: @@ -340,7 +340,7 @@ def check_for_self_lock_key(rule, door, parent_counter, key_layout, world): rule.small_location = next(iter(counter.free_locations)) -def find_inverted_counter(door, parent_counter, key_layout, world): +def find_inverted_counter(door, parent_counter, key_layout, world, player): # open all doors in counter counter = open_all_counter(parent_counter, key_layout, door=door) max_counter = find_max_counter(key_layout) @@ -352,7 +352,7 @@ def find_inverted_counter(door, parent_counter, key_layout, world): inverted_counter.open_doors = dict_difference(max_counter.open_doors, counter.open_doors) inverted_counter.other_locations = dict_difference(max_counter.other_locations, counter.other_locations) for loc in inverted_counter.other_locations: - if important_location(loc, world): + if important_location(loc, world, player): inverted_counter.important_location = True return inverted_counter @@ -732,7 +732,7 @@ def create_key_counter(state, key_layout, world, player): key_counter = KeyCounter(key_layout.max_chests) key_counter.child_doors.update(dict.fromkeys(unique_doors(state.small_doors+state.big_doors))) for loc in state.found_locations: - if important_location(loc, world): + if important_location(loc, world, player): key_counter.important_location = True key_counter.other_locations[loc] = None elif loc.event and 'Small Key' in loc.item.name: @@ -755,14 +755,14 @@ def create_key_counter(state, key_layout, world, player): return key_counter -def important_location(loc, world): +def important_location(loc, world, player): important_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden'] - if world.mode == 'standard' or world.doorShuffle == 'crossed': + if world.mode[player] == 'standard' or world.doorShuffle[player] == 'crossed': important_locations.append('Hyrule Dungeon Cellblock') return '- Prize' in loc.name or loc.name in important_locations -def create_odd_key_counter(door, parent_counter, key_layout, world): +def create_odd_key_counter(door, parent_counter, key_layout, world, player): odd_counter = KeyCounter(key_layout.max_chests) next_counter = find_next_counter(door, parent_counter, key_layout) odd_counter.free_locations = dict_difference(next_counter.free_locations, parent_counter.free_locations) @@ -770,7 +770,7 @@ def create_odd_key_counter(door, parent_counter, key_layout, world): odd_counter.child_doors = dict_difference(next_counter.child_doors, parent_counter.child_doors) odd_counter.other_locations = dict_difference(next_counter.other_locations, parent_counter.other_locations) for loc in odd_counter.other_locations: - if important_location(loc, world): + if important_location(loc, world, player): odd_counter.important_location = True return odd_counter diff --git a/Main.py b/Main.py index eac92a0f..4e0091c5 100644 --- a/Main.py +++ b/Main.py @@ -145,7 +145,7 @@ def main(args, seed=None): logger.info('Patching ROM.') player_names = parse_names_string(args.names) - outfilebase = 'ER_%s' % (args.outputname if args.outputname else world.seed) + outfilebase = 'DR_%s' % (args.outputname if args.outputname else world.seed) rom_names = [] jsonout = {} @@ -225,7 +225,7 @@ def main(args, seed=None): def copy_world(world): # ToDo: Not good yet - ret = World(world.players, world.shuffle, world.door_shuffle, world.logic, world.mode, world.swords, world.difficulty, world.difficulty_adjustments, world.timer, world.progressive, world.goal, world.algorithm, world.accessibility, world.shuffle_ganon, world.retro, world.custom, world.customitemarray, world.hints) + ret = World(world.players, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords, world.difficulty, world.difficulty_adjustments, world.timer, world.progressive, world.goal, world.algorithm, world.accessibility, world.shuffle_ganon, world.retro, world.custom, world.customitemarray, world.hints) ret.required_medallions = world.required_medallions.copy() ret.swamp_patch_required = world.swamp_patch_required.copy() ret.ganon_at_pyramid = world.ganon_at_pyramid.copy() @@ -264,6 +264,8 @@ def copy_world(world): else: create_inverted_regions(ret, player) create_shops(ret, player) + create_doors(ret, player) + create_rooms(ret, player) create_dungeons(ret, player) copy_dynamic_regions_and_locations(world, ret) diff --git a/Rom.py b/Rom.py index d4e9b5c9..c93b98ab 100644 --- a/Rom.py +++ b/Rom.py @@ -579,7 +579,7 @@ def patch_rom(world, player, rom, enemized): patch_shuffled_dark_sanc(world, rom, player) # patch doors - if world.doorShuffle == 'crossed': + if world.doorShuffle[player] == 'crossed': rom.write_byte(0x151f1, 2) rom.write_byte(0x15270, 2) rom.write_byte(0x1597b, 2) @@ -1137,7 +1137,7 @@ def patch_rom(world, player, rom, enemized): # compasses showing dungeon count if world.clock_mode != 'off': rom.write_byte(0x18003C, 0x00) # Currently must be off if timer is on, because they use same HUD location - elif world.compassshuffle[player] or world.doorShuffle != 'vanilla': + elif world.compassshuffle[player] or world.doorShuffle[player] != 'vanilla': rom.write_byte(0x18003C, 0x01) # show on pickup else: rom.write_byte(0x18003C, 0x00)