Core: implement location_name_groups (#1502)

This commit is contained in:
alwaysintreble 2023-03-08 15:15:28 -06:00 committed by GitHub
parent d57314a407
commit e3deb822ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 1 deletions

View File

@ -361,6 +361,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
if game_world.data_version == 0 and game_world.game not in datapackage:
datapackage[game_world.game] = worlds.network_data_package["games"][game_world.game]
datapackage[game_world.game]["item_name_groups"] = game_world.item_name_groups
datapackage[game_world.game]["location_name_groups"] = game_world.location_name_groups
multidata = {
"slot_data": slot_data,

View File

@ -163,7 +163,9 @@ class Context:
item_names: typing.Dict[int, str] = Utils.KeyedDefaultDict(lambda code: f'Unknown item (ID:{code})')
item_name_groups: typing.Dict[str, typing.Dict[str, typing.Set[str]]]
location_names: typing.Dict[int, str] = Utils.KeyedDefaultDict(lambda code: f'Unknown location (ID:{code})')
location_name_groups: typing.Dict[str, typing.Dict[str, typing.Set[str]]]
all_item_and_group_names: typing.Dict[str, typing.Set[str]]
all_location_and_group_names: typing.Dict[str, typing.Set[str]]
non_hintable_names: typing.Dict[str, typing.Set[str]]
def __init__(self, host: str, port: int, server_password: str, password: str, location_check_points: int,
@ -232,7 +234,9 @@ class Context:
# init empty to satisfy linter, I suppose
self.gamespackage = {}
self.item_name_groups = {}
self.location_name_groups = {}
self.all_item_and_group_names = {}
self.all_location_and_group_names = {}
self.non_hintable_names = collections.defaultdict(frozenset)
self._load_game_data()
@ -244,6 +248,8 @@ class Context:
self.item_name_groups = {world_name: world.item_name_groups for world_name, world in
worlds.AutoWorldRegister.world_types.items()}
self.location_name_groups = {world_name: world.location_name_groups for world_name, world in
worlds.AutoWorldRegister.world_types.items()}
for world_name, world in worlds.AutoWorldRegister.world_types.items():
self.non_hintable_names[world_name] = world.hint_blacklist
@ -255,6 +261,8 @@ class Context:
self.location_names[location_id] = location_name
self.all_item_and_group_names[game_name] = \
set(game_package["item_name_to_id"]) | set(self.item_name_groups[game_name])
self.all_location_and_group_names[game_name] = \
set(game_package["location_name_to_id"]) | set(self.location_name_groups[game_name])
def item_names_for_game(self, game: str) -> typing.Optional[typing.Dict[str, int]]:
return self.gamespackage[game]["item_name_to_id"] if game in self.gamespackage else None
@ -428,10 +436,14 @@ class Context:
logging.info(f"Loading custom datapackage for game {game_name}")
self.gamespackage[game_name] = data
self.item_name_groups[game_name] = data["item_name_groups"]
self.location_name_groups[game_name] = data["location_name_groups"]
del data["item_name_groups"] # remove from datapackage, but keep in self.item_name_groups
del data["location_name_groups"]
self._init_game_data()
for game_name, data in self.item_name_groups.items():
self.read_data[f"item_name_groups_{game_name}"] = lambda lgame=game_name: self.item_name_groups[lgame]
for game_name, data in self.location_name_groups.items():
self.read_data[f"location_name_groups_{game_name}"] = lambda lgame=game_name: self.location_name_groups[lgame]
# saving
@ -1403,7 +1415,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
if game not in self.ctx.all_item_and_group_names:
self.output("Can't look up item/location for unknown game. Hint for ID instead.")
return False
names = self.ctx.location_names_for_game(game) \
names = self.ctx.all_location_and_group_names[game] \
if for_location else \
self.ctx.all_item_and_group_names[game]
hint_name, usable, response = get_intended_text(input_text, names)
@ -1419,6 +1431,11 @@ class ClientMessageProcessor(CommonCommandProcessor):
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item_name))
elif not for_location and hint_name in self.ctx.item_names_for_game(game): # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name)
elif hint_name in self.ctx.location_name_groups[game]: # location group name
hints = []
for loc_name in self.ctx.location_name_groups[game][hint_name]:
if loc_name in self.ctx.location_names_for_game(game):
hints.extend(collect_hint_location_name(self.ctx, self.client.team, self.client.slot, loc_name))
else: # location name
hints = collect_hint_location_name(self.ctx, self.client.team, self.client.slot, hint_name)

View File

@ -739,6 +739,11 @@ class VerifyKeys:
for item_name in self.value:
new_value |= world.item_name_groups.get(item_name, {item_name})
self.value = new_value
elif self.convert_name_groups and self.verify_location_name:
new_value = type(self.value)()
for loc_name in self.value:
new_value |= world.location_name_groups.get(loc_name, {loc_name})
self.value = new_value
if self.verify_item_name:
for item_name in self.value:
if item_name not in world.item_names:

View File

@ -149,6 +149,9 @@ class World(metaclass=AutoWorldRegister):
item_name_groups: ClassVar[Dict[str, Set[str]]] = {}
"""maps item group names to sets of items. Example: {"Weapons": {"Sword", "Bow"}}"""
location_name_groups: ClassVar[Dict[str, Set[str]]] = {}
"""maps location group names to sets of locations. Example: {"Sewer": {"Sewer Key Drop 1", "Sewer Key Drop 2"}}"""
data_version: ClassVar[int] = 1
"""
increment this every time something in your world's names/id mappings changes.

View File

@ -117,6 +117,75 @@ class ALTTPWorld(World):
option_definitions = alttp_options
topology_present = True
item_name_groups = item_name_groups
location_name_groups = {
"Blind's Hideout": {"Blind's Hideout - Top", "Blind's Hideout - Left", "Blind's Hideout - Right",
"Blind's Hideout - Far Left", "Blind's Hideout - Far Right"},
"Kakariko Well": {"Kakariko Well - Top", "Kakariko Well - Left", "Kakariko Well - Middle",
"Kakariko Well - Right", "Kakariko Well - Bottom"},
"Mini Moldorm Cave": {"Mini Moldorm Cave - Far Left", "Mini Moldorm Cave - Left", "Mini Moldorm Cave - Right",
"Mini Moldorm Cave - Far Right", "Mini Moldorm Cave - Generous Guy"},
"Paradox Cave": {"Paradox Cave Lower - Far Left", "Paradox Cave Lower - Left", "Paradox Cave Lower - Right",
"Paradox Cave Lower - Far Right", "Paradox Cave Lower - Middle", "Paradox Cave Upper - Left",
"Paradox Cave Upper - Right"},
"Hype Cave": {"Hype Cave - Top", "Hype Cave - Middle Right", "Hype Cave - Middle Left",
"Hype Cave - Bottom", "Hype Cave - Generous Guy"},
"Hookshot Cave": {"Hookshot Cave - Top Right", "Hookshot Cave - Top Left", "Hookshot Cave - Bottom Right",
"Hookshot Cave - Bottom Left"},
"Hyrule Castle": {"Hyrule Castle - Boomerang Chest", "Hyrule Castle - Map Chest",
"Hyrule Castle - Zelda's Chest", "Sewers - Dark Cross", "Sewers - Secret Room - Left",
"Sewers - Secret Room - Middle", "Sewers - Secret Room - Right"},
"Eastern Palace": {"Eastern Palace - Compass Chest", "Eastern Palace - Big Chest",
"Eastern Palace - Cannonball Chest", "Eastern Palace - Big Key Chest",
"Eastern Palace - Map Chest", "Eastern Palace - Boss"},
"Desert Palace": {"Desert Palace - Big Chest", "Desert Palace - Torch", "Desert Palace - Map Chest",
"Desert Palace - Compass Chest", "Desert Palace Big Key Chest", "Desert Palace - Boss"},
"Tower of Hera": {"Tower of Hera - Basement Cage", "Tower of Hera - Map Chest", "Tower of Hera - Big Key Chest",
"Tower of Hera - Compass Chest", "Tower of Hera - Big Chest", "Tower of Hera - Boss"},
"Palace of Darkness": {"Palace of Darkness - Shooter Room", "Palace of Darkness - The Arena - Bridge",
"Palace of Darkness - Stalfos Basement", "Palace of Darkness - Big Key Chest",
"Palace of Darkness - The Arena - Ledge", "Palace of Darkness - Map Chest",
"Palace of Darkness - Compass Chest", "Palace of Darkness - Dark Basement - Left",
"Palace of Darkness - Dark Basement - Right", "Palace of Darkness - Dark Maze - Top",
"Palace of Darkness - Dark Maze - Bottom", "Palace of Darkness - Big Chest",
"Palace of Darkness - Harmless Hellway", "Palace of Darkness - Boss"},
"Swamp Palace": {"Swamp Palace - Entrance", "Swamp Palace - Swamp Palace - Map Chest",
"Swamp Palace - Big Chest", "Swamp Palace - Compass Chest", "Swamp Palace - Big Key Chest",
"Swamp Palace - West Chest", "Swamp Palace - Flooded Room - Left",
"Swamp Palace - Flooded Room - Right", "Swamp Palace - Waterfall Room", "Swamp Palace - Boss"},
"Thieves' Town": {"Thieves' Town - Big Key Chest", "Thieves' Town - Map Chest", "Thieves' Town - Compass Chest",
"Thieves' Town - Ambush Chest", "Thieves' Town - Attic", "Thieves' Town - Big Chest",
"Thieves' Town - Blind's Cell", "Thieves' Town - Boss"},
"Skull Woods": {"Skull Woods - Map Chest", "Skull Woods - Pinball Room", "Skull Woods - Compass Chest",
"Skull Woods - Pot Prison", "Skull Woods - Big Chest", "Skull Woods - Big Key Chest",
"Skull Woods - Bridge Room", "Skull Woods - Boss"},
"Ice Palace": {"Ice Palace - Compass Chest", "Ice Palace - Freezor Chest", "Ice Palace - Big Chest",
"Ice Palace - Freezor Chest", "Ice Palace - Big Chest", "Ice Palace - Iced T Room",
"Ice Palace - Spike Room", "Ice Palace - Big Key Chest", "Ice Palace - Map Chest",
"Ice Palace - Boss"},
"Misery Mire": {"Misery Mire - Big Chest", "Misery Mire - Map Chest", "Misery Mire - Main Lobby",
"Misery Mire - Bridge Chest", "Misery Mire - Spike Chest", "Misery Mire - Compass Chest",
"Misery Mire - Big Key Chest", "Misery Mire - Boss"},
"Turtle Rock": {"Turtle Rock - Compass Chest", "Turtle Rock - Roller Room - Left",
"Turtle Rock - Roller Room - Right", "Turtle Room - Chain Chomps", "Turtle Rock - Big Key Chest",
"Turtle Rock - Big Chest", "Turtle Rock - Crystaroller Room",
"Turtle Rock - Eye Bridge - Bottom Left", "Turtle Rock - Eye Bridge - Bottom Right",
"Turtle Rock - Eye Bridge - Top Left", "Turtle Rock - Eye Bridge - Top Right", "Turtle Rock - Boss"},
"Ganons Tower": {"Ganons Tower - Bob's Torch", "Ganon's Tower - Hope Room - Left",
"Ganons Tower - Hope Room - Right", "Ganons Tower - Tile Room",
"Ganons Tower - Compass Room - Top Left", "Ganons Tower - Compass Room - Top Right",
"Ganons Tower - Compass Room - Bottom Left", "Ganons Tower - Compass Room - Bottom Left",
"Ganons Tower - DMs Room - Top Left", "Ganons Tower - DMs Room - Top Right",
"Ganons Tower - DMs Room - Bottom Left", "Ganons Tower - DMs Room - Bottom Right",
"Ganons Tower - Map Chest", "Ganons Tower - Firesnake Room",
"Ganons Tower - Randomizer Room - Top Left", "Ganons Tower - Randomizer Room - Top Right",
"Ganons Tower - Randomizer Room - Bottom Left", "Ganons Tower - Randomizer Room - Bottom Right",
"Ganons Tower - Bob's Chest", "Ganons Tower - Big Chest", "Ganons Tower - Big Key Room - Left",
"Ganons Tower - Big Key Room - Right", "Ganons Tower - Big Key Chest",
"Ganons Tower - Mini Helmasaur Room - Left", "Ganons Tower - Mini Helmasaur Room - Right",
"Ganons Tower - Pre-Moldorm Room", "Ganons Tower - Validation Chest"},
"Ganons Tower Climb": {"Ganons Tower - Mini Helmasaur Room - Left", "Ganons Tower - Mini Helmasaur Room - Right",
"Ganons Tower - Pre-Moldorm Room", "Ganons Tower - Validation Chest"},
}
hint_blacklist = {"Triforce"}
item_name_to_id = {name: data.item_code for name, data in item_table.items() if type(data.item_code) == int}