ItemLinks: move item links to events, mess up their logic in doing so and lock them behind plando option "item_links" until they're fixed.

This commit is contained in:
Fabian Dill
2022-02-17 06:07:11 +01:00
parent 311fb04647
commit c525c80b49
5 changed files with 82 additions and 67 deletions

View File

@@ -21,11 +21,13 @@ else:
auto_world = object
class Group(TypedDict):
class Group(TypedDict, total=False):
name: str
game: str
world: auto_world
players: Set[int]
item_pool: Set[str]
replacement_items: Dict[int, Optional[str]]
class MultiWorld():
@@ -43,6 +45,7 @@ class MultiWorld():
groups: Dict[int, Group]
is_race: bool = False
precollected_items: Dict[int, List[Item]]
state: CollectionState
class AttributeProxy():
def __init__(self, rule):
@@ -65,7 +68,6 @@ class MultiWorld():
self.seed = None
self.seed_name: str = "Unavailable"
self.precollected_items = {player: [] for player in self.player_ids}
self.state = CollectionState(self)
self._cached_entrances = None
self._cached_locations = None
self._entrance_cache = {}
@@ -145,6 +147,9 @@ class MultiWorld():
self.worlds = {}
self.slot_seeds = {}
def get_all_ids(self):
return self.player_ids + tuple(self.groups)
def add_group(self, name: str, game: str, players: Set[int] = frozenset()) -> Tuple[int, Group]:
"""Create a group with name and return the assigned player ID and group.
If a group of this name already exists, the set of players is extended instead of creating a new one."""
@@ -166,33 +171,11 @@ class MultiWorld():
getattr(self, option_key)[new_id] = option(option.default)
self.worlds[new_id] = world_type(self, new_id)
self.player_name[new_id] = name
# TODO: remove when LttP are transitioned over
self.difficulty_requirements[new_id] = self.difficulty_requirements[next(iter(players))]
new_group = self.groups[new_id] = Group(name=name, game=game, players=players,
world=self.worlds[new_id])
# instead of collect/remove overwrites, should encode sending as Events so they show up in spoiler log
def group_collect(state, item) -> bool:
changed = False
for player in new_group["players"]:
max(self.worlds[player].collect(state, item), changed)
return changed
def group_remove(state, item) -> bool:
changed = False
for player in new_group["players"]:
max(self.worlds[player].remove(state, item), changed)
return changed
new_world = new_group["world"]
new_world.collect = group_collect
new_world.remove = group_remove
self.worlds[new_id] = new_world
return new_id, new_group
def get_player_groups(self, player) -> Set[int]:
@@ -221,6 +204,35 @@ class MultiWorld():
setattr(self, option_key, getattr(args, option_key, {}))
self.worlds[player] = world_type(self, player)
item_links = {}
for player in self.player_ids:
for item_link in self.item_links[player].value:
if item_link["name"] in item_links:
item_links[item_link["name"]]["players"][player] = item_link["replacement_item"]
item_links[item_link["name"]]["item_pool"] &= set(item_link["item_pool"])
else:
if item_link["name"] in self.player_name.values():
raise Exception(f"Cannot name a ItemLink group the same as a player ({item_link['name']}).")
item_links[item_link["name"]] = {
"players": {player: item_link["replacement_item"]},
"item_pool": set(item_link["item_pool"]),
"game": self.game[player]
}
for name, item_link in item_links.items():
current_item_name_groups = AutoWorld.AutoWorldRegister.world_types[item_link["game"]].item_name_groups
pool = set()
for item in item_link["item_pool"]:
pool |= current_item_name_groups.get(item, {item})
item_link["item_pool"] = pool
for group_name, item_link in item_links.items():
game = item_link["game"]
group_id, group = self.add_group(group_name, game, set(item_link["players"]))
group["item_pool"] = item_link["item_pool"]
group["replacement_items"] = item_link["players"]
# intended for unittests
def set_default_common_options(self):
for option_key, option in Options.common_options.items():
@@ -544,12 +556,12 @@ class CollectionState(object):
def __init__(self, parent: MultiWorld):
self.prog_items = Counter()
self.world = parent
self.reachable_regions = {player: set() for player in range(1, parent.players + 1)}
self.blocked_connections = {player: set() for player in range(1, parent.players + 1)}
self.reachable_regions = {player: set() for player in parent.get_all_ids()}
self.blocked_connections = {player: set() for player in parent.get_all_ids()}
self.events = set()
self.path = {}
self.locations_checked = set()
self.stale = {player: True for player in range(1, parent.players + 1)}
self.stale = {player: True for player in parent.get_all_ids()}
for items in parent.precollected_items.values():
for item in items:
self.collect(item, True)
@@ -591,9 +603,9 @@ class CollectionState(object):
ret = CollectionState(self.world)
ret.prog_items = self.prog_items.copy()
ret.reachable_regions = {player: copy.copy(self.reachable_regions[player]) for player in
range(1, self.world.players + 1)}
self.reachable_regions}
ret.blocked_connections = {player: copy.copy(self.blocked_connections[player]) for player in
range(1, self.world.players + 1)}
self.blocked_connections}
ret.events = copy.copy(self.events)
ret.path = copy.copy(self.path)
ret.locations_checked = copy.copy(self.locations_checked)