From d3676948c3cd3c898d445c63234b39c536611a0b Mon Sep 17 00:00:00 2001 From: skizzerz Date: Sat, 14 Nov 2015 21:04:43 -0600 Subject: [PATCH] Add !fspectate command Admin-only command (can be !fallowed) to spectate deadchat or wolfchat. The person spectating is not revealed to anyone in the chat, however they can see everyone in that chat. If used outside of debug mode, it is restricted a la !revealroles where it cannot be used by an alive player or an active vengeful ghost. --- messages/en.json | 7 ++- src/utilities.py | 8 ++- src/wolfgame.py | 128 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 108 insertions(+), 35 deletions(-) diff --git a/messages/en.json b/messages/en.json index 07acc22..9db6b17 100644 --- a/messages/en.json +++ b/messages/en.json @@ -745,5 +745,10 @@ "available_modes": "Available game modes: \u0002", "process_exited": "Process %s exited with %s %d", "admin_fleave_deadchat": "You have forced {0} to leave the deadchat.", - "available_mode_setters_help": "Votes to make a specific game mode more likely. Available game mode setters: " + "available_mode_setters_help": "Votes to make a specific game mode more likely. Available game mode setters: ", + "fspectate_help": "Usage: fspectate [on|off]", + "fspectate_restricted": "You may not spectate while playing.", + "fspectate_deadchat_disabled": "Deadchat is disabled and may not be spectated.", + "fspectate_on": "You are now spectating {0}.", + "fspectate_off": "You are no longer spectating {0}." } diff --git a/src/utilities.py b/src/utilities.py index 94cfc6b..4cb75cf 100644 --- a/src/utilities.py +++ b/src/utilities.py @@ -23,6 +23,8 @@ def mass_mode(cli, md_param, md_plain): cli.mode(botconfig.CHANNEL, "".join(md_plain)) def mass_privmsg(cli, targets, msg, notice=False, privmsg=False): + if not targets: + return if not notice and not privmsg: msg_targs = [] not_targs = [] @@ -151,5 +153,7 @@ def relay_wolfchat_command(cli, nick, message, roles, is_wolf_command=False, is_ wcwolves = var.list_players(wcroles) wcwolves.remove(nick) - if wcwolves: - mass_privmsg(cli, wcwolves, message) + mass_privmsg(cli, wcwolves, message) + mass_privmsg(cli, var.SPECTATING_WOLFCHAT, "[wolfchat] " + message) + +# vim: set expandtab:sw=4:ts=4: diff --git a/src/wolfgame.py b/src/wolfgame.py index 80d5d4a..1ab3698 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -424,6 +424,8 @@ def reset(): var.PLAYERS.clear() var.DCED_PLAYERS.clear() var.DISCONNECTED.clear() + var.SPECTATING_WOLFCHAT = set() + var.SPECTATING_DEADCHAT = set() reset() @@ -1052,12 +1054,14 @@ def join_deadchat(cli, *all_nicks): else: msg = messages["multiple_joined_deadchat"].format("\u0002, \u0002".join(nicks[:-1]), nicks[-1]) mass_privmsg(cli, var.DEADCHAT_PLAYERS, msg) + mass_privmsg(cli, var.SPECTATING_DEADCHAT, "[deadchat] " + msg) mass_privmsg(cli, nicks, messages["joined_deadchat"]) people = var.DEADCHAT_PLAYERS | set(nicks) mass_privmsg(cli, nicks, messages["list_deadchat"].format(", ".join(people))) var.DEADCHAT_PLAYERS.update(nicks) + var.SPECTATING_DEADCHAT.difference_update(nicks) def leave_deadchat(cli, nick, force=""): if not var.ENABLE_DEADCHAT: @@ -1067,12 +1071,15 @@ def leave_deadchat(cli, nick, force=""): return var.DEADCHAT_PLAYERS.remove(nick) + msg = "" if force: pm(cli, nick, messages["force_leave_deadchat"].format(force)) - mass_privmsg(cli, var.DEADCHAT_PLAYERS, messages["player_force_leave_deadchat"].format(nick, force)) + msg = messages["player_force_leave_deadchat"].format(nick, force) else: pm(cli, nick, messages["leave_deadchat"]) - mass_privmsg(cli, var.DEADCHAT_PLAYERS, messages["player_left_deadchat"].format(nick)) + msg = messages["player_left_deadchat"].format(nick) + mass_privmsg(cli, var.DEADCHAT_PLAYERS, msg) + mass_privmsg(cli, var.SPECTATING_DEADCHAT, "[deadchat] " + msg) @cmd("deadchat", pm=True) def deadchat_pref(cli, nick, chan, rest): @@ -3403,6 +3410,16 @@ def rename_player(cli, prefix, nick): var.ENTRANCED.remove(prefix) var.ENTRANCED.add(nick) + if prefix in var.DEADCHAT_PLAYERS: + var.DEADCHAT_PLAYERS.remove(prefix) + var.DEADCHAT_PLAYERS.add(nick) + if prefix in var.SPECTATING_DEADCHAT: + var.SPECTATING_DEADCHAT.remove(prefix) + var.SPECTATING_DEADCHAT.add(nick) + if prefix in var.SPECTATING_WOLFCHAT: + var.SPECTATING_WOLFCHAT.remove(prefix) + var.SPECTATING_WOLFCHAT.add(nick) + event = Event("rename_player", {}) event.dispatch(cli, var, prefix, nick) @@ -3672,6 +3689,9 @@ def leave(cli, what, nick, why=""): msg = (messages["leave_death_no_reveal"] + "{1}").format(nick, population) make_stasis(nick, var.LEAVE_STASIS_PENALTY) cli.msg(botconfig.CHANNEL, msg) + var.SPECTATING_WOLFCHAT.discard(nick) + var.SPECTATING_DEADCHAT.discard(nick) + leave_deadchat(cli, nick) if what not in ("badnick", "account") and nick in var.USERS: var.USERS[nick]["modes"] = set() var.USERS[nick]["moded"] = set() @@ -6421,13 +6441,14 @@ def relay(cli, nick, chan, rest): if nick not in pl: if var.ENABLE_DEADCHAT and nick in var.DEADCHAT_PLAYERS: + to_msg = var.DEADCHAT_PLAYERS - {nick} if rest.startswith("\u0001ACTION"): rest = rest[7:-1] - mass_privmsg(cli, [x for x in var.DEADCHAT_PLAYERS if x != nick], - "* \u0002{0}\u0002{1}".format(nick, rest)) + mass_privmsg(cli, to_msg, "* \u0002{0}\u0002{1}".format(nick, rest)) + mass_privmsg(cli, var.SPECTATING_DEADCHAT, "* [deadchat] \u0002{0}\u0002{1}".format(nick, rest)) else: - mass_privmsg(cli, [x for x in var.DEADCHAT_PLAYERS if x != nick], - "\u0002{0}\u0002 says: {1}".format(nick, rest)) + mass_privmsg(cli, to_msg, "\u0002{0}\u0002 says: {1}".format(nick, rest)) + mass_privmsg(cli, var.SPECTATING_DEADCHAT, "[deadchat] \u0002{0}\u0002 says: {1}".format(nick, rest)) elif nick in badguys and len(badguys) > 1: # handle wolfchat toggles @@ -6443,13 +6464,14 @@ def relay(cli, nick, chan, rest): return badguys.remove(nick) + to_msg = set(badguys) & var.PLAYERS.keys() if rest.startswith("\u0001ACTION"): rest = rest[7:-1] - mass_privmsg(cli, [x for x in badguys if x in var.PLAYERS], - "* \u0002{0}\u0002{1}".format(nick, rest)) + mass_privmsg(cli, to_msg, "* \u0002{0}\u0002{1}".format(nick, rest)) + mass_privmsg(cli, var.SPECTATING_WOLFCHAT, "* [wolfchat] \u0002{0}\u0002{1}".format(nick, rest)) else: - mass_privmsg(cli, [x for x in badguys if x in var.PLAYERS], - "\u0002{0}\u0002 says: {1}".format(nick, rest)) + mass_privmsg(cli, to_msg, "\u0002{0}\u0002 says: {1}".format(nick, rest)) + mass_privmsg(cli, var.SPECTATING_WOLFCHAT, "[wolfchat] \u0002{0}\u0002 says: {1}".format(nick, rest)) @handle_error def transition_night(cli): @@ -7396,6 +7418,8 @@ def start(cli, nick, chan, forced = False, restart = ""): var.DULLAHAN_TARGETS = {} var.DEADCHAT_PLAYERS = set() + var.SPECTATING_WOLFCHAT = set() + var.SPECTATING_DEADCHAT = set() for role, count in addroles.items(): if role in var.TEMPLATE_RESTRICTIONS.keys(): @@ -8801,6 +8825,67 @@ def fact(cli, raw_nick, chan, rest): """Act through the bot as an action.""" _say(cli, raw_nick, rest, "fact", action=True) +def can_run_restricted_cmd(nick): + # if allowed in normal games, restrict it so that it can only be used by dead players and + # non-players (don't allow active vengeful ghosts either). + # also don't allow in-channel (e.g. make it pm only) + + if botconfig.DEBUG_MODE: + return True + + pl = var.list_players() + [vg for (vg, against) in var.VENGEFUL_GHOSTS.items() if not against.startswith("!")] + + if nick in pl: + return False + + if nick in var.USERS and var.USERS[nick]["account"] in [var.USERS[player]["account"] for player in pl if player in var.USERS]: + return False + + hostmask = var.USERS[nick]["ident"] + "@" + var.USERS[nick]["host"] + if nick in var.USERS and hostmask in [var.USERS[player]["ident"] + "@" + var.USERS[player]["host"] for player in pl if player in var.USERS]: + return False + + return True + +@cmd("fspectate", admin_only=True, pm=True, phases=("day", "night")) +def fspectate(cli, nick, chan, rest): + """Spectate wolfchat or deadchat.""" + if not can_run_restricted_cmd(nick): + pm(cli, nick, messages["fspectate_restricted"]) + return + + params = rest.split(" ") + on = "on" + if not len(params): + pm(cli, nick, messages["fspectate_help"]) + return + elif len(params) > 1: + on = params[1].lower() + what = params[0].lower() + if what not in ("wolfchat", "deadchat") or on not in ("on", "off"): + pm(cli, nick, messages["fspectate_help"]) + return + + if on == "off": + if what == "wolfchat": + var.SPECTATING_WOLFCHAT.discard(nick) + else: + var.SPECTATING_DEADCHAT.discard(nick) + pm(cli, nick, messages["fspectate_off"].format(what)) + else: + players = [] + if what == "wolfchat": + var.SPECTATING_WOLFCHAT.add(nick) + players = (p for p in var.list_players() if in_wolflist(p, p)) + elif var.ENABLE_DEADCHAT: + var.SPECTATING_DEADCHAT.add(nick) + players = var.DEADCHAT_PLAYERS + else: + pm(cli, nick, messages["fspectate_deadchat_disabled"]) + return + pm(cli, nick, messages["fspectate_on"].format(what)) + pm(cli, nick, "People in {0}: {1}".format(what, ", ".join(players))) + before_debug_mode_commands = list(COMMANDS.keys()) if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: @@ -8828,29 +8913,8 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: @cmd("revealroles", admin_only=True, pm=True, phases=("day", "night")) def revealroles(cli, nick, chan, rest): """Reveal role information.""" - def is_authorized(): - # if allowed in normal games, restrict it so that it can only be used by dead players and - # non-players (don't allow active vengeful ghosts either). - # also don't allow in-channel (e.g. make it pm only) - if botconfig.DEBUG_MODE: - return True - - pl = var.list_players() + [vg for (vg, against) in var.VENGEFUL_GHOSTS.items() if not against.startswith("!")] - - if nick in pl: - return False - - if nick in var.USERS and var.USERS[nick]["account"] in [var.USERS[player]["account"] for player in pl if player in var.USERS]: - return False - - hostmask = var.USERS[nick]["ident"] + "@" + var.USERS[nick]["host"] - if nick in var.USERS and hostmask in [var.USERS[player]["ident"] + "@" + var.USERS[player]["host"] for player in pl if player in var.USERS]: - return False - - return True - - if not is_authorized(): + if not can_run_restricted_cmd(nick): if chan == nick: pm(cli, nick, messages["temp_invalid_perms"]) else: