Core: change Region caching to on_change from on-miss-strategy (#2366)

This commit is contained in:
Fabian Dill
2023-10-29 19:47:37 +01:00
committed by GitHub
parent d9b076a687
commit 3e0d1d4e1c
24 changed files with 265 additions and 202 deletions

View File

@@ -293,7 +293,6 @@ def generate_itempool(world):
loc.access_rule = lambda state: has_triforce_pieces(state, player)
region.locations.append(loc)
multiworld.clear_location_cache()
multiworld.push_item(loc, ItemFactory('Triforce', player), False)
loc.event = True

View File

@@ -786,8 +786,8 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
# patch items
for location in world.get_locations():
if location.player != player or location.address is None or location.shop_slot is not None:
for location in world.get_locations(player):
if location.address is None or location.shop_slot is not None:
continue
itemid = location.item.code if location.item is not None else 0x5A
@@ -2247,7 +2247,7 @@ def write_strings(rom, world, player):
tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!'
hint_locations = HintLocations.copy()
local_random.shuffle(hint_locations)
all_entrances = [entrance for entrance in world.get_entrances() if entrance.player == player]
all_entrances = list(world.get_entrances(player))
local_random.shuffle(all_entrances)
# First we take care of the one inconvenient dungeon in the appropriately simple shuffles.

View File

@@ -197,8 +197,13 @@ def global_rules(world, player):
# determines which S&Q locations are available - hide from paths since it isn't an in-game location
for exit in world.get_region('Menu', player).exits:
exit.hide_path = True
set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.can_reach('Old Man', 'Location', player))
try:
old_man_sq = world.get_entrance('Old Man S&Q', player)
except KeyError:
pass # it doesn't exist, should be dungeon-only unittests
else:
old_man = world.get_location("Old Man", player)
set_rule(old_man_sq, lambda state: old_man.can_reach(state))
set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player))
@@ -1526,16 +1531,16 @@ def set_bunny_rules(world: MultiWorld, player: int, inverted: bool):
# Helper functions to determine if the moon pearl is required
if inverted:
def is_bunny(region):
return region.is_light_world
return region and region.is_light_world
def is_link(region):
return region.is_dark_world
return region and region.is_dark_world
else:
def is_bunny(region):
return region.is_dark_world
return region and region.is_dark_world
def is_link(region):
return region.is_light_world
return region and region.is_light_world
def get_rule_to_add(region, location = None, connecting_entrance = None):
# In OWG, a location can potentially be superbunny-mirror accessible or
@@ -1603,21 +1608,20 @@ def set_bunny_rules(world: MultiWorld, player: int, inverted: bool):
return options_to_access_rule(possible_options)
# Add requirements for bunny-impassible caves if link is a bunny in them
for region in [world.get_region(name, player) for name in bunny_impassable_caves]:
for region in (world.get_region(name, player) for name in bunny_impassable_caves):
if not is_bunny(region):
continue
rule = get_rule_to_add(region)
for exit in region.exits:
add_rule(exit, rule)
for region_exit in region.exits:
add_rule(region_exit, rule)
paradox_shop = world.get_region('Light World Death Mountain Shop', player)
if is_bunny(paradox_shop):
add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop))
# Add requirements for all locations that are actually in the dark world, except those available to the bunny, including dungeon revival
for entrance in world.get_entrances():
if entrance.player == player and is_bunny(entrance.connected_region):
for entrance in world.get_entrances(player):
if is_bunny(entrance.connected_region):
if world.logic[player] in ['minorglitches', 'owglitches', 'hybridglitches', 'nologic'] :
if entrance.connected_region.type == LTTPRegionType.Dungeon:
if entrance.parent_region.type != LTTPRegionType.Dungeon and entrance.connected_region.name in OverworldGlitchRules.get_invalid_bunny_revival_dungeons():

View File

@@ -348,7 +348,6 @@ def create_shops(world, player: int):
loc.item = ItemFactory(GetBeemizerItem(world, player, 'Nothing'), player)
loc.shop_slot_disabled = True
shop.region.locations.append(loc)
world.clear_location_cache()
class ShopData(NamedTuple):
@@ -619,6 +618,4 @@ def create_dynamic_shop_locations(world, player):
if shop.type == ShopType.TakeAny:
loc.shop_slot_disabled = True
shop.region.locations.append(loc)
world.clear_location_cache()
loc.shop_slot = i

View File

@@ -585,27 +585,26 @@ class ALTTPWorld(World):
for player in checks_in_area:
checks_in_area[player]["Total"] = 0
for location in multiworld.get_locations():
if location.game == cls.game and type(location.address) is int:
main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
if location.parent_region.dungeon:
dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
'Inverted Ganons Tower': 'Ganons Tower'} \
.get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
checks_in_area[location.player][dungeonname].append(location.address)
elif location.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif location.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
else:
assert False, "Unknown Location area."
# TODO: remove Total as it's duplicated data and breaks consistent typing
checks_in_area[location.player]["Total"] += 1
for location in multiworld.get_locations(player):
if location.game == cls.game and type(location.address) is int:
main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
if location.parent_region.dungeon:
dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
'Inverted Ganons Tower': 'Ganons Tower'} \
.get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
checks_in_area[location.player][dungeonname].append(location.address)
elif location.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif location.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
else:
assert False, "Unknown Location area."
# TODO: remove Total as it's duplicated data and breaks consistent typing
checks_in_area[location.player]["Total"] += 1
multidata["checks_in_area"].update(checks_in_area)

View File

@@ -1,5 +1,5 @@
from BaseClasses import CollectionState, ItemClassification
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import mandatory_connections, connect_simple
from worlds.alttp.ItemPool import difficulties
from worlds.alttp.Items import ItemFactory