Core: Attribute per slot random directly to the World and discourage using MultiWorld's random (#1649)

* add a random object to the World

* use it in The Messenger

* the worlds don't exist until the end of set options

* set seed in lttp tests

* use world.random for shop shuffle
This commit is contained in:
Aaron Wagener 2023-07-02 05:50:14 -05:00 committed by GitHub
parent 6a88d5aa79
commit a6ba185c55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 17 additions and 5 deletions

View File

@ -81,6 +81,7 @@ class MultiWorld():
random: random.Random
per_slot_randoms: Dict[int, random.Random]
"""Deprecated. Please use `self.random` instead."""
class AttributeProxy():
def __init__(self, rule):
@ -242,6 +243,7 @@ class MultiWorld():
setattr(self, option_key, getattr(args, option_key, {}))
self.worlds[player] = world_type(self, player)
self.worlds[player].random = self.per_slot_randoms[player]
def set_item_links(self):
item_links = {}

View File

@ -203,6 +203,9 @@ class World(metaclass=AutoWorldRegister):
location_names: ClassVar[Set[str]]
"""set of all potential location names"""
random: random.Random
"""This world's random object. Should be used for any randomization needed in world for this player slot."""
zip_path: ClassVar[Optional[pathlib.Path]] = None
"""If loaded from a .apworld, this is the Path to it."""
__file__: ClassVar[str]

View File

@ -14,6 +14,7 @@ from worlds import AutoWorld
class TestDungeon(unittest.TestCase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -15,6 +15,7 @@ from worlds import AutoWorld
class TestInverted(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -15,6 +15,7 @@ class TestInvertedBombRules(unittest.TestCase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
self.multiworld.mode[1] = "inverted"
args = Namespace
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():

View File

@ -16,6 +16,7 @@ from worlds import AutoWorld
class TestInvertedMinor(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -17,6 +17,7 @@ from worlds import AutoWorld
class TestInvertedOWG(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -16,6 +16,7 @@ from worlds import AutoWorld
class TestMinor(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -17,6 +17,7 @@ from worlds import AutoWorld
class TestVanillaOWG(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -15,6 +15,7 @@ from worlds import AutoWorld
class TestVanilla(TestBase):
def setUp(self):
self.multiworld = MultiWorld(1)
self.multiworld.set_seed(None)
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].option_definitions.items():
setattr(args, name, {1: option.from_any(option.default)})

View File

@ -75,13 +75,12 @@ FIGURINES: Dict[str, ShopData] = {
def shuffle_shop_prices(world: MessengerWorld) -> Tuple[Dict[str, int], Dict[str, int]]:
shop_price_mod = world.multiworld.shop_price[world.player].value
shop_price_planned = world.multiworld.shop_price_plan[world.player]
local_random: Random = world.multiworld.per_slot_randoms[world.player]
shop_prices: Dict[str, int] = {}
figurine_prices: Dict[str, int] = {}
for item, price in shop_price_planned.value.items():
if not isinstance(price, int):
price = local_random.choices(list(price.keys()), weights=list(price.values()))[0]
price = world.random.choices(list(price.keys()), weights=list(price.values()))[0]
if "Figurine" in item:
figurine_prices[item] = price
else:
@ -90,7 +89,7 @@ def shuffle_shop_prices(world: MessengerWorld) -> Tuple[Dict[str, int], Dict[str
remaining_slots = [item for item in [*SHOP_ITEMS, *FIGURINES] if item not in shop_price_planned.value]
for shop_item in remaining_slots:
shop_data = SHOP_ITEMS.get(shop_item, FIGURINES.get(shop_item))
price = local_random.randint(shop_data.min_price, shop_data.max_price)
price = world.random.randint(shop_data.min_price, shop_data.max_price)
adjusted_price = min(int(price * shop_price_mod / 100), 5000)
if "Figurine" in shop_item:
figurine_prices[shop_item] = adjusted_price

View File

@ -102,7 +102,7 @@ class MessengerWorld(World):
# make a list of all notes except those in the player's defined starting inventory, and adjust the
# amount we need to put in the itempool and precollect based on that
notes = [note for note in NOTES if note not in self.multiworld.precollected_items[self.player]]
self.multiworld.per_slot_randoms[self.player].shuffle(notes)
self.random.shuffle(notes)
precollected_notes_amount = NotesNeeded.range_end - \
self.multiworld.notes_needed[self.player] - \
(len(NOTES) - len(notes))
@ -129,7 +129,7 @@ class MessengerWorld(World):
filler_pool = dict(list(FILLER.items())[2:]) if remaining_fill < 10 else FILLER
itempool += [self.create_item(filler_item)
for filler_item in
self.multiworld.random.choices(
self.random.choices(
list(filler_pool),
weights=list(filler_pool.values()),
k=remaining_fill