diff --git a/BaseClasses.py b/BaseClasses.py index 14b48db3..4d054e17 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -4,6 +4,7 @@ import copy from enum import Enum, unique import logging import json +import functools from collections import OrderedDict, Counter, deque from typing import Union, Optional, List, Dict, NamedTuple, Iterable import secrets @@ -160,6 +161,10 @@ class World(object): region.world = self self._region_cache[region.player][region.name] = region + @functools.cached_property + def world_name_lookup(self): + return {self.player_names[player_id][0]: player_id for player_id in self.player_ids} + def _recache(self): """Rebuild world cache""" for region in self.regions: diff --git a/Fill.py b/Fill.py index 6a7219c9..0e797be1 100644 --- a/Fill.py +++ b/Fill.py @@ -359,7 +359,7 @@ def swap_location_item(location_1: Location, location_2: Location, check_locked= def distribute_planned(world): - world_name_lookup = {world.player_names[player_id][0]: player_id for player_id in world.player_ids} + world_name_lookup = world.world_name_lookup for player in world.player_ids: placement: PlandoItem diff --git a/Gui.py b/Gui.py index 296d7bae..d04f7352 100755 --- a/Gui.py +++ b/Gui.py @@ -236,7 +236,8 @@ def guiMain(args=None): shuffleVar.set('vanilla') shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', - 'dungeonsfull', 'dungeonssimple') + 'dungeonsfull', 'dungeonssimple', "same simple", "same restricted", "same full", + "same crossed", "same insanity", "same dungeonsfull", "same dungeonssimple") shuffleOptionMenu.pack(side=RIGHT) shuffleLabel = Label(shuffleFrame, text='Entrance shuffle') shuffleLabel.pack(side=LEFT) @@ -417,6 +418,9 @@ def guiMain(args=None): guiargs.accessibility = accessibilityVar.get() guiargs.algorithm = algorithmVar.get() guiargs.shuffle = shuffleVar.get() + if "same " in guiargs.shuffle: + guiargs.shuffle = guiargs.shuffle[5:] + "-" + str(seedVar.get() if seedVar.get() else + random.randint(0, 2**64)) guiargs.heartbeep = rom_vars.heartbeepVar.get() guiargs.heartcolor = rom_vars.heartcolorVar.get() guiargs.fastmenu = rom_vars.fastMenuVar.get() diff --git a/Main.py b/Main.py index 2d22db67..1f1f0c2a 100644 --- a/Main.py +++ b/Main.py @@ -170,12 +170,22 @@ def main(args, seed=None): {"vanilla", "dungeonssimple", "dungeonsfull", "simple", "restricted", "full"}: world.fix_fake_world[player] = False + old_random = world.random + + # seeded entrance shuffle + if "-" in world.shuffle[player]: + shuffle, seed = world.shuffle[player].split("-") + world.random = random.Random(int(seed)) + world.shuffle[player] = shuffle + if world.mode[player] != 'inverted': link_entrances(world, player) mark_light_world_regions(world, player) else: link_inverted_entrances(world, player) mark_dark_world_regions(world, player) + + world.random = old_random plando_connect(world, player) logger.info('Generating Item Pool.') diff --git a/playerSettings.yaml b/playerSettings.yaml index f212f49c..0a524049 100644 --- a/playerSettings.yaml +++ b/playerSettings.yaml @@ -87,6 +87,9 @@ entrance_shuffle: # Documentation: https://alttpr.com/en/options#entrance_shuffl full: 0 # Less strict than restricted crossed: 0 # Less strict than full insanity: 0 # Very few grouping rules. Good luck + # you can also define entrance shuffle seed, like so: + crossed-1000: 0 # using this method, you can have the same layout as another player and share entrance information + # however, many other settings like logic, world state, retro etc. may affect the shuffle result as well. goals: ganon: 50 # Climb GT, defeat Agahnim 2, and then kill Ganon fast_ganon: 0 # Only killing Ganon is required. However, items may still be placed in GT