MultiServer: remove location hinting from !hint and /hint; add /hint_location

This commit is contained in:
Fabian Dill 2022-01-16 02:20:37 +01:00
parent 6a7e1d920a
commit e74333cbd3
2 changed files with 49 additions and 24 deletions

View File

@ -543,7 +543,10 @@ async def on_client_joined(ctx: Context, client: Client):
f"{ctx.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1}) "
f"{verb} {ctx.games[client.slot]} has joined. "
f"Client({version_str}), {client.tags}).")
ctx.notify_client(client, "Now that you are connected, "
"you can use !help to list commands to run via the server."
"If your client supports it, "
"you may have additional local commands you can list with /help.")
ctx.client_connection_timers[client.team, client.slot] = datetime.datetime.now(datetime.timezone.utc)
@ -1088,7 +1091,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
self.output("Cheating is disabled.")
return False
def get_hints(self, input_text: str, explicit_location: bool = False) -> bool:
def get_hints(self, input_text: str, for_location: bool = False) -> bool:
points_available = get_client_points(self.ctx, self.client)
if not input_text:
hints = {hint.re_check(self.ctx, self.client.team) for hint in
@ -1100,20 +1103,21 @@ class ClientMessageProcessor(CommonCommandProcessor):
return True
else:
world = proxy_worlds[self.ctx.games[self.client.slot]]
item_name, usable, response = get_intended_text(input_text,
world.all_names if not explicit_location else world.location_names)
names = world.location_names if for_location else world.all_item_and_group_names
hint_name, usable, response = get_intended_text(input_text,
names)
if usable:
if item_name in world.hint_blacklist:
self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.")
if hint_name in world.hint_blacklist:
self.output(f"Sorry, \"{hint_name}\" is marked as non-hintable.")
hints = []
elif item_name in world.item_name_groups and not explicit_location:
elif not for_location and hint_name in world.item_name_groups: # item group name
hints = []
for item in world.item_name_groups[item_name]:
for item in world.item_name_groups[hint_name]:
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item))
elif item_name in world.item_names and not explicit_location: # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name)
elif not for_location and hint_name in world.item_names: # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name)
else: # location name
hints = collect_hints_location(self.ctx, self.client.team, self.client.slot, item_name)
hints = collect_hints_location(self.ctx, self.client.team, self.client.slot, hint_name)
cost = self.ctx.get_hint_cost(self.client.slot)
if hints:
new_hints = set(hints) - self.ctx.hints[self.client.team, self.client.slot]
@ -1175,8 +1179,8 @@ class ClientMessageProcessor(CommonCommandProcessor):
@mark_raw
def _cmd_hint(self, item_or_location: str = "") -> bool:
"""Use !hint {item_name/location_name},
for example !hint Lamp or !hint Link's House to get a spoiler peek for that location or item.
"""Use !hint {item_name},
for example !hint Lamp to get a spoiler peek for that item.
If hint costs are on, this will only give you one new result,
you can rerun the command to get more in that case."""
return self.get_hints(item_or_location)
@ -1511,23 +1515,44 @@ class ServerCommandProcessor(CommonCommandProcessor):
self.output(response)
return False
def _cmd_hint(self, player_name: str, *item_or_location: str) -> bool:
"""Send out a hint for a player's item or location to their team"""
def _cmd_hint(self, player_name: str, *item: str) -> bool:
"""Send out a hint for a player's item to their team"""
seeked_player, usable, response = get_intended_text(player_name, self.ctx.player_names.values())
if usable:
team, slot = self.ctx.player_name_lookup[seeked_player]
item = " ".join(item_or_location)
item = " ".join(item)
world = proxy_worlds[self.ctx.games[slot]]
item, usable, response = get_intended_text(item, world.all_names)
item, usable, response = get_intended_text(item, world.all_item_and_group_names)
if usable:
if item in world.item_name_groups:
hints = []
for item in world.item_name_groups[item]:
hints.extend(collect_hints(self.ctx, team, slot, item))
elif item in world.item_names: # item name
else: # item name
hints = collect_hints(self.ctx, team, slot, item)
else: # location name
hints = collect_hints_location(self.ctx, team, slot, item)
if hints:
notify_hints(self.ctx, team, hints)
else:
self.output("No hints found.")
return True
else:
self.output(response)
return False
else:
self.output(response)
return False
def _cmd_hint_location(self, player_name: str, *location: str) -> bool:
"""Send out a hint for a player's location to their team"""
seeked_player, usable, response = get_intended_text(player_name, self.ctx.player_names.values())
if usable:
team, slot = self.ctx.player_name_lookup[seeked_player]
item = " ".join(location)
world = proxy_worlds[self.ctx.games[slot]]
item, usable, response = get_intended_text(item, world.location_names)
if usable:
hints = collect_hints_location(self.ctx, team, slot, item)
if hints:
notify_hints(self.ctx, team, hints)
else:

View File

@ -1,5 +1,5 @@
from __future__ import annotations
from typing import Dict, Set, Tuple, List, Optional, TextIO
from typing import Dict, Set, Tuple, List, Optional, TextIO, Any
from BaseClasses import MultiWorld, Item, CollectionState, Location
from Options import Option
@ -8,7 +8,7 @@ from Options import Option
class AutoWorldRegister(type):
world_types: Dict[str, World] = {}
def __new__(cls, name, bases, dct):
def __new__(cls, name: str, bases, dct: Dict[str, Any]):
# filter out any events
dct["item_name_to_id"] = {name: id for name, id in dct["item_name_to_id"].items() if id}
dct["location_name_to_id"] = {name: id for name, id in dct["location_name_to_id"].items() if id}
@ -19,7 +19,7 @@ class AutoWorldRegister(type):
# build rest
dct["item_names"] = frozenset(dct["item_name_to_id"])
dct["location_names"] = frozenset(dct["location_name_to_id"])
dct["all_names"] = dct["item_names"] | dct["location_names"] | set(dct.get("item_name_groups", {}))
dct["all_item_and_group_names"] = frozenset(dct["item_names"] | set(dct.get("item_name_groups", {})))
# construct class
new_class = super().__new__(cls, name, bases, dct)
@ -71,7 +71,7 @@ class World(metaclass=AutoWorldRegister):
options: Dict[str, type(Option)] = {} # link your Options mapping
game: str # name the game
topology_present: bool = False # indicate if world type has any meaningful layout/pathing
all_names: Set[str] = frozenset() # gets automatically populated with all item, item group and location names
all_item_and_group_names: Set[str] = frozenset() # gets automatically populated with all item and item group names
# map names to their IDs
item_name_to_id: Dict[str, int] = {}