ItemLinks: allow linking replacement items as well (#1274)
This commit is contained in:
parent
449973687b
commit
7c3af68e59
|
@ -26,6 +26,7 @@ class Group(TypedDict, total=False):
|
|||
replacement_items: Dict[int, Optional[str]]
|
||||
local_items: Set[str]
|
||||
non_local_items: Set[str]
|
||||
link_replacement: bool
|
||||
|
||||
|
||||
class MultiWorld():
|
||||
|
@ -222,27 +223,32 @@ class MultiWorld():
|
|||
|
||||
def set_item_links(self):
|
||||
item_links = {}
|
||||
|
||||
replacement_prio = [False, True, None]
|
||||
for player in self.player_ids:
|
||||
for item_link in self.item_links[player].value:
|
||||
if item_link["name"] in item_links:
|
||||
if item_links[item_link["name"]]["game"] != self.game[player]:
|
||||
raise Exception(f"Cannot ItemLink across games. Link: {item_link['name']}")
|
||||
item_links[item_link["name"]]["players"][player] = item_link["replacement_item"]
|
||||
item_links[item_link["name"]]["item_pool"] &= set(item_link["item_pool"])
|
||||
item_links[item_link["name"]]["exclude"] |= set(item_link.get("exclude", []))
|
||||
item_links[item_link["name"]]["local_items"] &= set(item_link.get("local_items", []))
|
||||
item_links[item_link["name"]]["non_local_items"] &= set(item_link.get("non_local_items", []))
|
||||
current_link = item_links[item_link["name"]]
|
||||
current_link["players"][player] = item_link["replacement_item"]
|
||||
current_link["item_pool"] &= set(item_link["item_pool"])
|
||||
current_link["exclude"] |= set(item_link.get("exclude", []))
|
||||
current_link["local_items"] &= set(item_link.get("local_items", []))
|
||||
current_link["non_local_items"] &= set(item_link.get("non_local_items", []))
|
||||
current_link["link_replacement"] = min(current_link["link_replacement"],
|
||||
replacement_prio.index(item_link["link_replacement"]))
|
||||
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']}) ({self.get_player_name(player)}).")
|
||||
raise Exception(f"Cannot name a ItemLink group the same as a player ({item_link['name']}) "
|
||||
f"({self.get_player_name(player)}).")
|
||||
item_links[item_link["name"]] = {
|
||||
"players": {player: item_link["replacement_item"]},
|
||||
"item_pool": set(item_link["item_pool"]),
|
||||
"exclude": set(item_link.get("exclude", [])),
|
||||
"game": self.game[player],
|
||||
"local_items": set(item_link.get("local_items", [])),
|
||||
"non_local_items": set(item_link.get("non_local_items", []))
|
||||
"non_local_items": set(item_link.get("non_local_items", [])),
|
||||
"link_replacement": replacement_prio.index(item_link["link_replacement"]),
|
||||
}
|
||||
|
||||
for name, item_link in item_links.items():
|
||||
|
@ -267,10 +273,12 @@ class MultiWorld():
|
|||
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"]
|
||||
group["local_items"] = item_link["local_items"]
|
||||
group["non_local_items"] = item_link["non_local_items"]
|
||||
group["link_replacement"] = replacement_prio[item_link["link_replacement"]]
|
||||
|
||||
# intended for unittests
|
||||
def set_default_common_options(self):
|
||||
|
|
12
Main.py
12
Main.py
|
@ -210,11 +210,15 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
|
|||
while itemcount > len(world.itempool):
|
||||
items_to_add = []
|
||||
for player in group["players"]:
|
||||
if group["replacement_items"][player]:
|
||||
items_to_add.append(
|
||||
AutoWorld.call_single(world, "create_item", player, group["replacement_items"][player]))
|
||||
if group["link_replacement"]:
|
||||
item_player = group_id
|
||||
else:
|
||||
items_to_add.append(AutoWorld.call_single(world, "create_filler", player))
|
||||
item_player = player
|
||||
if group["replacement_items"][player]:
|
||||
items_to_add.append(AutoWorld.call_single(world, "create_item", item_player,
|
||||
group["replacement_items"][player]))
|
||||
else:
|
||||
items_to_add.append(AutoWorld.call_single(world, "create_filler", item_player))
|
||||
world.random.shuffle(items_to_add)
|
||||
world.itempool.extend(items_to_add[:itemcount - len(world.itempool)])
|
||||
|
||||
|
|
|
@ -927,7 +927,8 @@ class ItemLinks(OptionList):
|
|||
Optional("exclude"): [And(str, len)],
|
||||
"replacement_item": Or(And(str, len), None),
|
||||
Optional("local_items"): [And(str, len)],
|
||||
Optional("non_local_items"): [And(str, len)]
|
||||
Optional("non_local_items"): [And(str, len)],
|
||||
Optional("link_replacement"): Or(None, bool),
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -950,6 +951,7 @@ class ItemLinks(OptionList):
|
|||
return pool
|
||||
|
||||
def verify(self, world, player_name: str, plando_options) -> None:
|
||||
link: dict
|
||||
super(ItemLinks, self).verify(world, player_name, plando_options)
|
||||
existing_links = set()
|
||||
for link in self.value:
|
||||
|
@ -974,7 +976,9 @@ class ItemLinks(OptionList):
|
|||
|
||||
intersection = local_items.intersection(non_local_items)
|
||||
if intersection:
|
||||
raise Exception(f"item_link {link['name']} has {intersection} items in both its local_items and non_local_items pool.")
|
||||
raise Exception(f"item_link {link['name']} has {intersection} "
|
||||
f"items in both its local_items and non_local_items pool.")
|
||||
link.setdefault("link_replacement", None)
|
||||
|
||||
|
||||
per_game_common_options = {
|
||||
|
|
|
@ -184,6 +184,7 @@ A Link to the Past:
|
|||
- Fire Rod
|
||||
- Ice Rod
|
||||
replacement_item: "Rupee (1)"
|
||||
link_replacement: true
|
||||
triggers:
|
||||
- option_category: A Link to the Past
|
||||
option_name: smallkey_shuffle
|
||||
|
@ -241,7 +242,7 @@ Timespinner:
|
|||
* `exclude_locations` forces a not important item to be placed on the `Cave 45` location.
|
||||
* `item_links`
|
||||
* For `A Link to the Past` all players in the `rods` item link group will share their fire and ice rods and the player
|
||||
items will be replaced with single rupees.
|
||||
items will be replaced with single rupees. The rupee will also be shared among those players.
|
||||
* For `Timespinner` all players in the `TSAll` item link group will share their entire item pool and the `Twin Pyramid
|
||||
Key` and `Timespinner Wheel` will be forced among the worlds of those in the group. The `null` replacement item will,
|
||||
instead of forcing a specific chosen item, allow the generator to randomly pick a filler item to replace the player items.
|
||||
|
|
Loading…
Reference in New Issue