From 6d5ddf3cadd579265319d3a60dd6e8b05fca6153 Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Tue, 20 Sep 2022 01:31:08 +0200 Subject: [PATCH] MultiServer: allow using IDs for hints --- MultiServer.py | 181 ++++++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 70 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index b0307cb8..9f0865d4 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -222,11 +222,11 @@ class Context: self.all_item_and_group_names[game_name] = \ set(game_package["item_name_to_id"]) | set(self.item_name_groups[game_name]) - def item_names_for_game(self, game: str) -> typing.Dict[str, int]: - return self.gamespackage[game]["item_name_to_id"] + 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 - def location_names_for_game(self, game: str) -> typing.Dict[str, int]: - return self.gamespackage[game]["location_name_to_id"] + def location_names_for_game(self, game: str) -> typing.Optional[typing.Dict[str, int]]: + return self.gamespackage[game]["location_name_to_id"] if game in self.gamespackage else None # General networking async def send_msgs(self, endpoint: Endpoint, msgs: typing.Iterable[dict]) -> bool: @@ -901,14 +901,14 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations: typi ctx.save() -def collect_hints(ctx: Context, team: int, slot: int, item_name: str) -> typing.List[NetUtils.Hint]: +def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, str]) -> typing.List[NetUtils.Hint]: hints = [] slots: typing.Set[int] = {slot} for group_id, group in ctx.groups.items(): if slot in group: slots.add(group_id) - seeked_item_id = ctx.item_names_for_game(ctx.games[slot])[item_name] + seeked_item_id = item if isinstance(item, int) else ctx.item_names_for_game(ctx.games[slot])[item] for finding_player, check_data in ctx.locations.items(): for location_id, (item_id, receiving_player, item_flags) in check_data.items(): if receiving_player in slots and item_id == seeked_item_id: @@ -1336,13 +1336,33 @@ class ClientMessageProcessor(CommonCommandProcessor): self.output(f"A hint costs {self.ctx.get_hint_cost(self.client.slot)} points. " f"You have {points_available} points.") return True + + elif input_text.isnumeric(): + game = self.ctx.games[self.client.slot] + hint_id = int(input_text) + hint_name = self.ctx.item_names[hint_id] \ + if not for_location and hint_id in self.ctx.item_names \ + else self.ctx.location_names[hint_id] \ + if for_location and hint_id in self.ctx.location_names \ + else None + if hint_name in self.ctx.non_hintable_names[game]: + self.output(f"Sorry, \"{hint_name}\" is marked as non-hintable.") + hints = [] + elif not for_location: + hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_id) + else: + hints = collect_hint_location_id(self.ctx, self.client.team, self.client.slot, hint_id) + else: game = self.ctx.games[self.client.slot] + 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) \ if for_location else \ self.ctx.all_item_and_group_names[game] - hint_name, usable, response = get_intended_text(input_text, - names) + hint_name, usable, response = get_intended_text(input_text, names) + if usable: if hint_name in self.ctx.non_hintable_names[game]: self.output(f"Sorry, \"{hint_name}\" is marked as non-hintable.") @@ -1356,63 +1376,65 @@ class ClientMessageProcessor(CommonCommandProcessor): hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name) else: # location name hints = collect_hint_location_name(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] - old_hints = set(hints) - new_hints - if old_hints: - notify_hints(self.ctx, self.client.team, list(old_hints)) - if not new_hints: - self.output("Hint was previously used, no points deducted.") - if new_hints: - found_hints = [hint for hint in new_hints if hint.found] - not_found_hints = [hint for hint in new_hints if not hint.found] - if not not_found_hints: # everything's been found, no need to pay - can_pay = 1000 - elif cost: - can_pay = int((points_available // cost) > 0) # limit to 1 new hint per call - else: - can_pay = 1000 - - self.ctx.random.shuffle(not_found_hints) - # By popular vote, make hints prefer non-local placements - not_found_hints.sort(key=lambda hint: int(hint.receiving_player != hint.finding_player)) - - hints = found_hints - while can_pay > 0: - if not not_found_hints: - break - hint = not_found_hints.pop() - hints.append(hint) - can_pay -= 1 - self.ctx.hints_used[self.client.team, self.client.slot] += 1 - points_available = get_client_points(self.ctx, self.client) - - if not_found_hints: - if hints and cost and int((points_available // cost) == 0): - self.output( - f"There may be more hintables, however, you cannot afford to pay for any more. " - f" You have {points_available} and need at least " - f"{self.ctx.get_hint_cost(self.client.slot)}.") - elif hints: - self.output( - "There may be more hintables, you can rerun the command to find more.") - else: - self.output(f"You can't afford the hint. " - f"You have {points_available} points and need at least " - f"{self.ctx.get_hint_cost(self.client.slot)}.") - notify_hints(self.ctx, self.client.team, hints) - self.ctx.save() - return True - - else: - self.output("Nothing found. Item/Location may not exist.") - return False else: self.output(response) return False + if hints: + cost = self.ctx.get_hint_cost(self.client.slot) + new_hints = set(hints) - self.ctx.hints[self.client.team, self.client.slot] + old_hints = set(hints) - new_hints + if old_hints: + notify_hints(self.ctx, self.client.team, list(old_hints)) + if not new_hints: + self.output("Hint was previously used, no points deducted.") + if new_hints: + found_hints = [hint for hint in new_hints if hint.found] + not_found_hints = [hint for hint in new_hints if not hint.found] + + if not not_found_hints: # everything's been found, no need to pay + can_pay = 1000 + elif cost: + can_pay = int((points_available // cost) > 0) # limit to 1 new hint per call + else: + can_pay = 1000 + + self.ctx.random.shuffle(not_found_hints) + # By popular vote, make hints prefer non-local placements + not_found_hints.sort(key=lambda hint: int(hint.receiving_player != hint.finding_player)) + + hints = found_hints + while can_pay > 0: + if not not_found_hints: + break + hint = not_found_hints.pop() + hints.append(hint) + can_pay -= 1 + self.ctx.hints_used[self.client.team, self.client.slot] += 1 + points_available = get_client_points(self.ctx, self.client) + + if not_found_hints: + if hints and cost and int((points_available // cost) == 0): + self.output( + f"There may be more hintables, however, you cannot afford to pay for any more. " + f" You have {points_available} and need at least " + f"{self.ctx.get_hint_cost(self.client.slot)}.") + elif hints: + self.output( + "There may be more hintables, you can rerun the command to find more.") + else: + self.output(f"You can't afford the hint. " + f"You have {points_available} points and need at least " + f"{self.ctx.get_hint_cost(self.client.slot)}.") + notify_hints(self.ctx, self.client.team, hints) + self.ctx.save() + return True + + else: + self.output("Nothing found. Item/Location may not exist.") + return False + @mark_raw def _cmd_hint(self, item_name: str = "") -> bool: """Use !hint {item_name}, @@ -1860,17 +1882,25 @@ class ServerCommandProcessor(CommonCommandProcessor): 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_name = " ".join(item_name) game = self.ctx.games[slot] - item_name, usable, response = get_intended_text(item_name, self.ctx.all_item_and_group_names[game]) + full_name = " ".join(item_name) + + if full_name.isnumeric(): + item, usable, response = int(full_name), True, None + elif game in self.ctx.all_item_and_group_names: + item, usable, response = get_intended_text(full_name, self.ctx.all_item_and_group_names[game]) + else: + self.output("Can't look up item for unknown game. Hint for ID instead.") + return False + if usable: - if item_name in self.ctx.item_name_groups[game]: + if game in self.ctx.item_name_groups and item in self.ctx.item_name_groups[game]: hints = [] - for item_name_from_group in self.ctx.item_name_groups[game][item_name]: + for item_name_from_group in self.ctx.item_name_groups[game][item]: if item_name_from_group in self.ctx.item_names_for_game(game): # ensure item has an ID hints.extend(collect_hints(self.ctx, team, slot, item_name_from_group)) - else: # item name - hints = collect_hints(self.ctx, team, slot, item_name) + else: # item name or id + hints = collect_hints(self.ctx, team, slot, item) if hints: notify_hints(self.ctx, team, hints) @@ -1891,11 +1921,22 @@ class ServerCommandProcessor(CommonCommandProcessor): 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] - location_name = " ".join(location_name) - location_name, usable, response = get_intended_text(location_name, - self.ctx.location_names_for_game(self.ctx.games[slot])) + game = self.ctx.games[slot] + full_name = " ".join(location_name) + + if full_name.isnumeric(): + location, usable, response = int(full_name), True, None + elif self.ctx.location_names_for_game(game) is not None: + location, usable, response = get_intended_text(full_name, self.ctx.location_names_for_game(game)) + else: + self.output("Can't look up location for unknown game. Hint for ID instead.") + return False + if usable: - hints = collect_hint_location_name(self.ctx, team, slot, location_name) + if isinstance(location, int): + hints = collect_hint_location_id(self.ctx, team, slot, location) + else: + hints = collect_hint_location_name(self.ctx, team, slot, location) if hints: notify_hints(self.ctx, team, hints) else: