Separate doorShuffle for each player
Add doorShuffle to spoiler metadata
This commit is contained in:
@@ -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()})
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
6
Main.py
6
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)
|
||||
|
||||
4
Rom.py
4
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)
|
||||
|
||||
Reference in New Issue
Block a user