From 0a6c6200abc34434571239b80b702744821db34b Mon Sep 17 00:00:00 2001 From: Fudster Date: Thu, 2 Feb 2017 02:31:51 +0000 Subject: [PATCH] Fix for #176 improve invalid role errors --- src/utilities.py | 31 +++++++++---------- src/wolfgame.py | 77 +++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/utilities.py b/src/utilities.py index a8cce65..7c4e7bd 100644 --- a/src/utilities.py +++ b/src/utilities.py @@ -15,7 +15,7 @@ __all__ = ["pm", "is_fake_nick", "mass_mode", "mass_privmsg", "reply", "is_owner", "is_admin", "plural", "singular", "list_players", "list_players_and_roles", "list_participants", "get_role", "get_roles", "get_reveal_role", "get_templates", "role_order", "break_long_message", - "complete_match", "get_victim", "get_nick", "InvalidModeException"] + "complete_match","complete_one_match", "get_victim", "get_nick", "InvalidModeException"] # message either privmsg or notice, depending on user settings def pm(cli, target, message): if is_fake_nick(target) and botconfig.DEBUG_MODE: @@ -418,18 +418,19 @@ def break_long_message(phrases, joinstr = " "): #completes a partial nickname or string from a list def complete_match(string, matches): - num_matches = 0 - bestmatch = string + possible_matches = set() for possible in matches: if string == possible: - return string, 1 + return [string] if possible.startswith(string) or possible.lstrip("[{\\^_`|}]").startswith(string): - bestmatch = possible - num_matches += 1 - if num_matches != 1: - return None, num_matches - else: - return bestmatch, 1 + possible_matches.add(possible) + return sorted(possible_matches) + +def complete_one_match(string, matches): + matches = complete_match(string,matches) + if len(matches) == 1: + return matches.pop() + return None #wrapper around complete_match() used for roles def get_victim(cli, nick, victim, in_chan, self_in_list=False, bot_in_list=False): @@ -444,20 +445,20 @@ def get_victim(cli, nick, victim, in_chan, self_in_list=False, bot_in_list=False pl.append(botconfig.NICK) pll.append(botconfig.NICK.lower()) - tempvictim, num_matches = complete_match(victim.lower(), pll) - if not tempvictim: + tempvictims = complete_match(victim.lower(), pll) + if len(tempvictims) != 1: #ensure messages about not being able to act on yourself work - if num_matches == 0 and nick.lower().startswith(victim.lower()): + if len(tempvictims) == 0 and nick.lower().startswith(victim.lower()): return nick reply(cli, nick, chan, messages["not_playing"].format(victim), private=True) return - return pl[pll.index(tempvictim)] #convert back to normal casing + return pl[pll.index(tempvictims.pop())] #convert back to normal casing # wrapper around complete_match() used for any nick on the channel def get_nick(cli, nick): ul = [x for x in var.USERS] ull = [x.lower() for x in var.USERS] - lnick, num_matches = complete_match(nick.lower(), ull) + lnick = complete_match(nick.lower(), ull) if not lnick: return None return ul[ull.index(lnick)] diff --git a/src/wolfgame.py b/src/wolfgame.py index 6caef03..fd576e5 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -2920,7 +2920,7 @@ def goat(cli, nick, chan, rest): if not rest: cli.notice(nick, messages["not_enough_parameters"]) - victim, _ = complete_match(rest.lower(), ull) + victim = complete_one_match(rest.lower(), ull) if not victim: cli.notice(nick, messages["goat_target_not_in_channel"].format(rest)) return @@ -4450,7 +4450,7 @@ def consecrate(cli, nick, chan, rest): dead = [x.nick for x in var.ALL_PLAYERS if x.nick not in alive] deadl = [x.lower() for x in dead] - tempvictim, num_matches = complete_match(victim.lower(), deadl) + tempvictim = complete_one_match(victim.lower(), deadl) if not tempvictim: pm(cli, nick, messages["consecrate_fail"].format(victim)) return @@ -4539,7 +4539,7 @@ def pray(cli, nick, chan, rest): pm(cli, nick, messages["not_enough_parameters"]) return # complete this as a match with other roles (so "cursed" can match "cursed villager" for instance) - role, _ = complete_match(what.lower(), var.ROLE_GUIDE.keys()) + role = complete_one_match(what.lower(), var.ROLE_GUIDE.keys()) if role is None: # typo, let them fix it pm(cli, nick, messages["specific_invalid_role"].format(what)) @@ -4780,7 +4780,7 @@ def change_sides(cli, nick, chan, rest, sendmsg=True): return team = re.split(" +", rest)[0] - team, _ = complete_match(team, ("villagers", "wolves")) + team = complete_one_match(team, ("villagers", "wolves")) if not team: pm(cli, nick, messages["turncoat_error"]) return @@ -6526,17 +6526,29 @@ def listroles(cli, nick, chan, rest): elif rest[0] and not rest[0].isdigit(): gamemode = rest[0] if gamemode not in var.GAME_MODES.keys(): - gamemode, _ = complete_match(rest[0], var.GAME_MODES.keys() - ["roles", "villagergame"] - var.DISABLED_GAMEMODES) + matches = complete_match(rest[0], var.GAME_MODES.keys() - {"roles", "villagergame"} - var.DISABLED_GAMEMODES) + if len(matches) > 1: + reply(cli, nick, chan, nick + " " + messages["invalid_mode"].format(rest[0], ", ".join(matches))) + rest = [] + roleindex = {} + return + if len(matches) == 0: + reply(cli, nick, chan, nick + " " + messages["invalid_mode_no_list"].format(rest[0], ", ".join(matches))) + rest = [] + roleindex = {} + return + else: + gamemode = matches[0] + validMode = gamemode in var.GAME_MODES.keys() and gamemode != "roles" and gamemode != "villagergame" and gamemode not in var.DISABLED_GAMEMODES if validMode and hasattr(var.GAME_MODES[gamemode][0](), "ROLE_GUIDE"): mode = var.GAME_MODES[gamemode][0]() - if hasattr(mode, "ROLE_INDEX") and hasattr(mode, "ROLE_GUIDE"): - roleindex = mode.ROLE_INDEX - roleguide = mode.ROLE_GUIDE - elif gamemode == "default" and "ROLE_INDEX" in var.ORIGINAL_SETTINGS and "ROLE_GUIDE" in var.ORIGINAL_SETTINGS: - roleindex = var.ORIGINAL_SETTINGS["ROLE_INDEX"] - roleguide = var.ORIGINAL_SETTINGS["ROLE_GUIDE"] - rest.pop(0) + if hasattr(mode, "ROLE_INDEX") and hasattr(mode, "ROLE_GUIDE"): + roleindex = mode.ROLE_INDEX + roleguide = mode.ROLE_GUIDE + elif gamemode == "default" and "ROLE_INDEX" in var.ORIGINAL_SETTINGS and "ROLE_GUIDE" in var.ORIGINAL_SETTINGS: + roleindex = var.ORIGINAL_SETTINGS["ROLE_INDEX"] + roleguide = var.ORIGINAL_SETTINGS["ROLE_GUIDE"] else: if validMode and not hasattr(var.GAME_MODES[gamemode][0](), "ROLE_GUIDE"): msg.append("{0}: {1}roles is disabled for the {2} game mode.".format(nick, botconfig.CMD_CHAR, gamemode)) @@ -6721,10 +6733,15 @@ def game_stats(cli, nick, chan, rest): if len(rest) and not rest[0].isdigit(): gamemode = rest[0] if gamemode != "all" and gamemode not in var.GAME_MODES.keys(): - gamemode, _ = complete_match(gamemode, var.GAME_MODES.keys()) - if not gamemode: - cli.notice(nick, messages["invalid_mode_no_list"].format(rest[0])) - return + matches = complete_match(gamemode, var.GAME_MODES.keys()) + if len(matches) == 1: + gamemode = matches[0] + if not matches: + cli.notice(nick, messages["invalid_mode_no_list"].format(rest[0])) + return + if len(matches) > 1: + cli.notice(nick, messages["invalid_mode"].format(rest[0], ", ".join(matches))) + return rest.pop(0) # Check for invalid input if len(rest) and rest[0].isdigit(): @@ -6791,11 +6808,14 @@ def player_stats(cli, nick, chan, rest): else: role = " ".join(params[1:]) if role not in var.ROLE_GUIDE.keys(): - match, _ = complete_match(role, var.ROLE_GUIDE.keys() | ["lover"]) - if not match: + matches = complete_match(role, var.ROLE_GUIDE.keys() | {"lover"}) + if not matches: reply(cli, nick, chan, messages["no_such_role"].format(role)) return - role = match + if len(matches) > 1: + reply(cli, nick, chan,nick, messages["invalid_mode"].format(role, ", ".join(matches))) + return + role = matches # Attempt to find the player's stats reply(cli, nick, chan, db.get_player_stats(acc, hostmask, role)) @@ -6813,13 +6833,16 @@ def vote_gamemode(var, wrapper, gamemode, doreply): return if gamemode not in var.GAME_MODES.keys(): - match, _ = complete_match(gamemode, var.GAME_MODES.keys() - ["roles", "villagergame"] - var.DISABLED_GAMEMODES) - if not match: - if doreply: - wrapper.pm(messages["invalid_mode_no_list"].format(gamemode)) + matches = complete_match(gamemode, var.GAME_MODES.keys() - {"roles", "villagergame"} - var.DISABLED_GAMEMODES) + if not matches: + wrapper.pm(messages["invalid_mode_no_list"].format(gamemode)) return - gamemode = match - + if len(matches) > 1: + wrapper.pm(messages["invalid_mode"].format(gamemode, ", ".join(matches))) + return + if len(matches) == 1: + gamemode = matches[0] + if gamemode != "roles" and gamemode != "villagergame" and gamemode not in var.DISABLED_GAMEMODES: if var.GAMEMODE_VOTES.get(wrapper.source.nick) == gamemode: wrapper.pm(messages["already_voted_game"].format(gamemode)) @@ -7167,9 +7190,9 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: if gamemode not in var.GAME_MODES.keys() - var.DISABLED_GAMEMODES: gamemode = gamemode.split()[0] - gamemode, _ = complete_match(gamemode, var.GAME_MODES.keys() - var.DISABLED_GAMEMODES) + gamemode = complete_one_match(gamemode, var.GAME_MODES.keys() - var.DISABLED_GAMEMODES) if not gamemode: - cli.notice(nick, messages["invalid_mode_no_list"].format(rest)) + cli.notice(nick, messages["invalid_mode_no_list"].format(rest.split()[0])) return parts[0] = gamemode