Add the new command API + converted commands
Converted commands mostly use some backwards-compatibility hack. Please don't mind it, I'll eventually get to it.
This commit is contained in:
parent
d590e7b727
commit
e8338d1ef6
@ -596,7 +596,6 @@
|
||||
"admin_forced_game": "A game mode has already been forced by an admin.",
|
||||
"vote_game_fail": "You can't vote for that game mode.",
|
||||
"fsend_usage": "Usage: {0}{1} <target> <message>",
|
||||
"wrong_channel": "You have to be in {0} to use this command.",
|
||||
"invalid_fsend_permissions": "You do not have permission to message this user or channel.",
|
||||
"temp_invalid_perms": "You are not allowed to use that command right now.",
|
||||
"fgame_success": "\u0002{0}\u0002 has changed the game settings successfully.",
|
||||
|
@ -27,7 +27,13 @@ class _States(Enum):
|
||||
def predicate(name):
|
||||
return not name.startswith(tuple(Features["CHANTYPES"]))
|
||||
|
||||
get = _channels.__getitem__
|
||||
def get(name, *, allow_none=False):
|
||||
try:
|
||||
return _channels[name]
|
||||
except KeyError:
|
||||
if allow_none:
|
||||
return None
|
||||
raise
|
||||
|
||||
def add(name, cli, key=""):
|
||||
"""Add and return a new channel, or an existing one if it exists."""
|
||||
|
@ -14,9 +14,10 @@ from oyoyo.parse import parse_nick
|
||||
|
||||
import botconfig
|
||||
import src.settings as var
|
||||
from src.dispatcher import MessageDispatcher
|
||||
from src.utilities import *
|
||||
from src import channels, users, logger, errlog, events
|
||||
from src.messages import messages
|
||||
from src import channels, users, logger, errlog, events
|
||||
|
||||
adminlog = logger.logger("audit.log")
|
||||
|
||||
@ -181,6 +182,121 @@ class handle_error:
|
||||
with print_traceback():
|
||||
return self.func(*args, **kwargs)
|
||||
|
||||
class command:
|
||||
def __init__(self, *commands, flag=None, owner_only=False, chan=True, pm=False,
|
||||
playing=False, silenced=False, phases=(), roles=(), users=None):
|
||||
|
||||
self.commands = frozenset(commands)
|
||||
self.flag = flag
|
||||
self.owner_only = owner_only
|
||||
self.chan = chan
|
||||
self.pm = pm
|
||||
self.playing = playing
|
||||
self.silenced = silenced
|
||||
self.phases = phases
|
||||
self.roles = roles
|
||||
self.users = users # iterable of users that can use the command at any time (should be a mutable object)
|
||||
self.func = None
|
||||
self.aftergame = False
|
||||
self.name = commands[0]
|
||||
self.alt_allowed = bool(flag or owner_only)
|
||||
|
||||
alias = False
|
||||
self.aliases = []
|
||||
for name in commands:
|
||||
for func in COMMANDS[name]:
|
||||
if func.owner_only != owner_only or func.flag != flag:
|
||||
raise ValueError("unmatching access levels for {0}".format(func.name))
|
||||
|
||||
COMMANDS[name].append(self)
|
||||
if name in botconfig.ALLOWED_ALT_CHANNELS_COMMANDS:
|
||||
self.alt_allowed = True
|
||||
if name in getattr(botconfig, "OWNERS_ONLY_COMMANDS", ()):
|
||||
self.owner_only = True
|
||||
if alias:
|
||||
self.aliases.append(name)
|
||||
alias = True
|
||||
|
||||
def __call__(self, func):
|
||||
if isinstance(func, command):
|
||||
func = func.func
|
||||
self.func = func
|
||||
self.__doc__ = func.__doc__
|
||||
return self
|
||||
|
||||
@handle_error
|
||||
def caller(self, cli, rawnick, chan, rest):
|
||||
user = users._add(cli, nick=rawnick) # FIXME
|
||||
|
||||
if users.equals(chan, users.Bot.nick): # PM
|
||||
target = users.Bot
|
||||
else:
|
||||
target = channels.add(chan, cli)
|
||||
|
||||
dispatcher = MessageDispatcher(user, target)
|
||||
|
||||
if (not self.pm and dispatcher.private) or (not self.chan and dispatcher.public):
|
||||
return # channel or PM command that we don't allow
|
||||
|
||||
if dispatcher.public and target is not channels.Main and not (self.flag or self.owner_only):
|
||||
if "" in self.commands or not self.alt_allowed:
|
||||
return # commands not allowed in alt channels
|
||||
|
||||
if "" in self.commands:
|
||||
return self.func(var, dispatcher, rest)
|
||||
|
||||
if self.phases and var.PHASE not in self.phases:
|
||||
return
|
||||
|
||||
if self.playing and (user.nick not in list_players() or user.nick in var.DISCONNECTED): # FIXME: Need to change this once list_players() / var.DISCONNECTED use User instances
|
||||
return
|
||||
|
||||
for role in self.roles:
|
||||
if user.nick in var.ROLES[role]: # FIXME: Need to change this once var.ROLES[role] holds User instances
|
||||
break
|
||||
else:
|
||||
if (self.users is not None and user not in self.users) or self.roles:
|
||||
return
|
||||
|
||||
if self.silenced and user.nick in var.SILENCED: # FIXME: Need to change this once var.SILENCED holds User instances
|
||||
dispatcher.pm(messages["silenced"])
|
||||
return
|
||||
|
||||
if self.roles or (self.users is not None and user in self.users):
|
||||
return self.func(var, dispatcher, rest) # don't check restrictions for role commands
|
||||
|
||||
if self.owner_only:
|
||||
if user.is_owner():
|
||||
adminlog(chan, rawnick, self.name, rest)
|
||||
return self.func(var, dispatcher, rest)
|
||||
|
||||
dispatcher.pm(messages["not_owner"])
|
||||
return
|
||||
|
||||
temp = user.lower()
|
||||
|
||||
flags = var.FLAGS[temp.rawnick] + var.FLAGS_ACCS[temp.account] # TODO: add flags handling to User
|
||||
|
||||
if self.flag and (user.is_admin() or user.is_owner()):
|
||||
adminlog(chan, rawnick, self.name, rest)
|
||||
return self.func(var, dispatcher, rest)
|
||||
|
||||
denied_commands = var.DENY[temp.rawnick] | var.DENY_ACCS[temp.account] # TODO: add denied commands handling to User
|
||||
|
||||
if self.commands & denied_commands:
|
||||
dispatcher.pm(messages["invalid_permissions"])
|
||||
return
|
||||
|
||||
if self.flag:
|
||||
if self.flag in flags:
|
||||
adminlog(chan, rawnick, self.name, rest)
|
||||
return self.func(var, dispatcher, rest)
|
||||
|
||||
dispatcher.pm(messages["not_an_admin"])
|
||||
return
|
||||
|
||||
return self.func(var, dispatcher, rest)
|
||||
|
||||
class cmd:
|
||||
def __init__(self, *cmds, raw_nick=False, flag=None, owner_only=False,
|
||||
chan=True, pm=False, playing=False, silenced=False,
|
||||
@ -222,8 +338,11 @@ class cmd:
|
||||
return self
|
||||
|
||||
@handle_error
|
||||
def caller(self, *args):
|
||||
largs = list(args)
|
||||
def caller(self, cli, rawnick, chan, rest):
|
||||
if users.equals(chan, users.Bot.nick):
|
||||
chan = users.parse_rawnick_as_dict(rawnick)["nick"]
|
||||
|
||||
largs = [cli, rawnick, chan, rest]
|
||||
|
||||
cli, rawnick, chan, rest = largs
|
||||
nick, mode, ident, host = parse_nick(rawnick)
|
||||
|
47
src/dispatcher.py
Normal file
47
src/dispatcher.py
Normal file
@ -0,0 +1,47 @@
|
||||
from src import channels, users
|
||||
from src import settings as var
|
||||
|
||||
from src.utilities import list_players
|
||||
|
||||
class MessageDispatcher:
|
||||
"""Dispatcher class for raw IRC messages."""
|
||||
|
||||
def __init__(self, source, target):
|
||||
self.source = source
|
||||
self.target = target
|
||||
|
||||
@property
|
||||
def private(self):
|
||||
return self.target is users.Bot
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
return self.target is not users.Bot
|
||||
|
||||
def pm(self, *messages, **kwargs):
|
||||
"""Send a private message or notice to the sender."""
|
||||
kwargs.setdefault("notice", self.public)
|
||||
self.source.send(*messages, **kwargs)
|
||||
|
||||
def send(self, *messages, **kwargs):
|
||||
"""Send a message to the channel or a private message."""
|
||||
if self.private:
|
||||
self.pm(*messages, **kwargs)
|
||||
else:
|
||||
self.target.send(*messages, **kwargs)
|
||||
|
||||
def reply(self, *messages, prefix_nick=False, **kwargs):
|
||||
"""Reply to the user, either in channel or privately."""
|
||||
first = ""
|
||||
if prefix_nick:
|
||||
first = "{0}: ".format(self.source.nick)
|
||||
if self.private:
|
||||
self.source.send(*messages, **kwargs)
|
||||
elif (self.target is channels.Main and
|
||||
((self.source not in list_players() and var.PHASE in var.GAME_PHASES) or
|
||||
(var.DEVOICE_DURING_NIGHT and var.PHASE == "night"))): # FIXME
|
||||
kwargs.setdefault("notice", True)
|
||||
self.source.send(*messages, **kwargs)
|
||||
else:
|
||||
kwargs.setdefault("first", first)
|
||||
self.target.send(*messages, **kwargs)
|
@ -10,7 +10,7 @@ import src.settings as var
|
||||
from src.utilities import *
|
||||
from src.messages import messages
|
||||
from src.decorators import handle_error
|
||||
from src import events
|
||||
from src import events, channels, users
|
||||
|
||||
def game_mode(name, minp, maxp, likelihood = 0):
|
||||
def decor(c):
|
||||
@ -1186,23 +1186,24 @@ class MaelstromMode(GameMode):
|
||||
if not var.ACCOUNTS_ONLY:
|
||||
self.DEAD_HOSTS.add(var.USERS[nick]["host"].lower())
|
||||
|
||||
def on_join(self, evt, cli, var, nick, chan, rest, forced=False):
|
||||
if var.PHASE != "day" or (nick != chan and chan != botconfig.CHANNEL):
|
||||
def on_join(self, evt, var, wrapper, message, forced=False):
|
||||
if var.PHASE != "day" or (wrapper.public and wrapper.target is not channels.Main):
|
||||
return
|
||||
if (irc_lower(nick) in (irc_lower(x) for x in var.ALL_PLAYERS) or
|
||||
irc_lower(var.USERS[nick]["account"]) in self.DEAD_ACCOUNTS or
|
||||
var.USERS[nick]["host"].lower() in self.DEAD_HOSTS):
|
||||
cli.notice(nick, messages["maelstrom_dead"])
|
||||
temp = wrapper.source.lower()
|
||||
if (temp.nick in (irc_lower(x) for x in var.ALL_PLAYERS) or # FIXME
|
||||
temp.account in self.DEAD_ACCOUNTS or
|
||||
temp.host in self.DEAD_HOSTS):
|
||||
wrapper.pm(messages["maelstrom_dead"])
|
||||
return
|
||||
if not forced and evt.data["join_player"](cli, nick, botconfig.CHANNEL, sanity=False):
|
||||
self._on_join(cli, var, nick, chan)
|
||||
if not forced and evt.data["join_player"](var, type(wrapper)(wrapper.source, channels.Main), sanity=False):
|
||||
self._on_join(var, wrapper)
|
||||
evt.prevent_default = True
|
||||
elif forced:
|
||||
# in fjoin, handle this differently
|
||||
jp = evt.data["join_player"]
|
||||
evt.data["join_player"] = lambda cli, nick, chan, who=None, forced=False: jp(cli, nick, chan, who=who, forced=forced, sanity=False) and self._on_join(cli, var, nick, chan)
|
||||
evt.data["join_player"] = lambda var, wrapper, who=None, forced=False: jp(var, wrapper, who=who, forced=forced, sanity=False) and self._on_join(var, wrapper)
|
||||
|
||||
def _on_join(self, cli, var, nick, chan):
|
||||
def _on_join(self, var, wrapper):
|
||||
role = random.choice(self.roles)
|
||||
|
||||
lpl = len(list_players()) + 1
|
||||
@ -1232,31 +1233,30 @@ class MaelstromMode(GameMode):
|
||||
elif role == "succubus":
|
||||
lsuccubi += 1
|
||||
|
||||
if self.chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ldemoniacs, ltraitors, lpipers, lsuccubi, 0, cli, end_game=False):
|
||||
return self._on_join(cli, var, nick, chan)
|
||||
if self.chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ldemoniacs, ltraitors, lpipers, lsuccubi, 0, wrapper.client, end_game=False):
|
||||
return self._on_join(var, wrapper)
|
||||
|
||||
var.ROLES[role].add(nick)
|
||||
var.ORIGINAL_ROLES[role].add(nick)
|
||||
var.FINAL_ROLES[nick] = role
|
||||
var.LAST_SAID_TIME[nick] = datetime.now()
|
||||
if nick in var.USERS:
|
||||
var.PLAYERS[nick] = var.USERS[nick]
|
||||
var.ROLES[role].add(wrapper.source.nick)
|
||||
var.ORIGINAL_ROLES[role].add(wrapper.source.nick)
|
||||
var.FINAL_ROLES[wrapper.source.nick] = role
|
||||
var.LAST_SAID_TIME[wrapper.source.nick] = datetime.now()
|
||||
if wrapper.source.nick in var.USERS:
|
||||
var.PLAYERS[wrapper.source.nick] = var.USERS[wrapper.source.nick]
|
||||
|
||||
if role == "doctor":
|
||||
lpl = len(list_players())
|
||||
var.DOCTORS[nick] = math.ceil(var.DOCTOR_IMMUNIZATION_MULTIPLIER * lpl)
|
||||
var.DOCTORS[wrapper.source.nick] = math.ceil(var.DOCTOR_IMMUNIZATION_MULTIPLIER * lpl)
|
||||
# let them know their role
|
||||
# FIXME: this is fugly
|
||||
from src.decorators import COMMANDS
|
||||
COMMANDS["myrole"][0].caller(cli, nick, chan, "")
|
||||
COMMANDS["myrole"][0].caller(wrapper.source.client, wrapper.source.nick, wrapper.target.name, "") # FIXME: New/old API
|
||||
# if they're a wolfchat role, alert the other wolves
|
||||
if role in var.WOLFCHAT_ROLES:
|
||||
relay_wolfchat_command(cli, nick, messages["wolfchat_new_member"].format(nick, role), var.WOLFCHAT_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||
relay_wolfchat_command(wrapper.source.client, wrapper.source.nick, messages["wolfchat_new_member"].format(wrapper.source.nick, role), var.WOLFCHAT_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||
# TODO: make this part of !myrole instead, no reason we can't give out wofllist in that
|
||||
wolves = list_players(var.WOLFCHAT_ROLES)
|
||||
pl = list_players()
|
||||
random.shuffle(pl)
|
||||
pl.remove(nick)
|
||||
pl.remove(wrapper.source.nick)
|
||||
for i, player in enumerate(pl):
|
||||
prole = get_role(player)
|
||||
if prole in var.WOLFCHAT_ROLES:
|
||||
@ -1266,7 +1266,7 @@ class MaelstromMode(GameMode):
|
||||
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
|
||||
elif player in var.ROLES["cursed villager"]:
|
||||
pl[i] = player + " (cursed)"
|
||||
pm(cli, nick, "Players: " + ", ".join(pl))
|
||||
wrapper.pm("Players: " + ", ".join(pl))
|
||||
|
||||
def role_attribution(self, evt, cli, var, chk_win_conditions, villagers):
|
||||
self.chk_win_conditions = chk_win_conditions
|
||||
|
@ -15,22 +15,19 @@ def on_privmsg(cli, rawnick, chan, msg, *, notice=False):
|
||||
if notice and "!" not in rawnick or not rawnick: # server notice; we don't care about those
|
||||
return
|
||||
|
||||
if not users.equals(chan, botconfig.NICK) and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
|
||||
if not users.equals(chan, users.Bot.nick) and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
|
||||
return
|
||||
|
||||
if (notice and ((not users.equals(chan, botconfig.NICK) and not botconfig.ALLOW_NOTICE_COMMANDS) or
|
||||
(users.equals(chan, botconfig.NICK) and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
||||
if (notice and ((not users.equals(chan, users.Bot.nick) and not botconfig.ALLOW_NOTICE_COMMANDS) or
|
||||
(users.equals(chan, users.Bot.nick) and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
||||
return # not allowed in settings
|
||||
|
||||
if users.equals(chan, botconfig.NICK):
|
||||
chan = users.parse_rawnick_as_dict(rawnick)["nick"]
|
||||
|
||||
for fn in decorators.COMMANDS[""]:
|
||||
fn.caller(cli, rawnick, chan, msg)
|
||||
|
||||
phase = var.PHASE
|
||||
for x in list(decorators.COMMANDS.keys()):
|
||||
if chan != users.parse_rawnick_as_dict(rawnick)["nick"] and not msg.lower().startswith(botconfig.CMD_CHAR):
|
||||
if not users.equals(chan, users.Bot.nick) and not msg.lower().startswith(botconfig.CMD_CHAR):
|
||||
break # channel message but no prefix; ignore
|
||||
if msg.lower().startswith(botconfig.CMD_CHAR+x):
|
||||
h = msg[len(x)+len(botconfig.CMD_CHAR):]
|
||||
|
@ -55,13 +55,13 @@ def dullahan_retract(cli, nick, chan, rest):
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
|
||||
@event_listener("player_win")
|
||||
def on_player_win(evt, cli, var, nick, role, winner, survived):
|
||||
def on_player_win(evt, var, user, role, winner, survived):
|
||||
if role != "dullahan":
|
||||
return
|
||||
alive = set(list_players())
|
||||
if nick in var.ENTRANCED:
|
||||
if user.nick in var.ENTRANCED:
|
||||
alive -= var.ROLES["succubus"]
|
||||
if not TARGETS[nick] & alive:
|
||||
if not TARGETS[user.nick] & alive:
|
||||
evt.data["iwon"] = True
|
||||
|
||||
@event_listener("del_player")
|
||||
@ -222,7 +222,7 @@ def on_myrole(evt, cli, var, nick):
|
||||
evt.data["messages"].append(messages["dullahan_targets_dead"])
|
||||
|
||||
@event_listener("revealroles_role")
|
||||
def on_revealroles_role(evt, cli, var, nickname, role):
|
||||
def on_revealroles_role(evt, var, wrapper, nickname, role):
|
||||
if role == "dullahan" and nickname in TARGETS:
|
||||
targets = TARGETS[nickname] - var.DEAD
|
||||
if targets:
|
||||
|
@ -53,7 +53,7 @@ brokentotem = set() # type: Set[str]
|
||||
|
||||
@cmd("give", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=var.TOTEM_ORDER)
|
||||
@cmd("totem", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=var.TOTEM_ORDER)
|
||||
def totem(cli, nick, chan, rest, prefix="You"):
|
||||
def totem(cli, nick, chan, rest, prefix="You"): # XXX: The transition_day_begin event needs updating alongside this
|
||||
"""Give a totem to a player."""
|
||||
victim = get_victim(cli, nick, re.split(" +",rest)[0], False, True)
|
||||
if not victim:
|
||||
@ -299,7 +299,7 @@ def on_chk_decision_lynch5(evt, cli, var, voters):
|
||||
evt.params.del_player(cli, target, True, end_game=False, killer_role="shaman", deadlist=evt.data["deadlist"], original=target, ismain=False)
|
||||
|
||||
@event_listener("player_win")
|
||||
def on_player_win(evt, cli, var, splr, rol, winner, survived):
|
||||
def on_player_win(evt, var, user, rol, winner, survived):
|
||||
if rol == "crazed shaman" and survived and not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
||||
evt.data["iwon"] = True
|
||||
|
||||
@ -320,7 +320,7 @@ def on_transition_day_begin(evt, cli, var):
|
||||
ps.remove(succubus)
|
||||
if ps:
|
||||
target = random.choice(ps)
|
||||
totem.func(cli, shaman, shaman, target, messages["random_totem_prefix"])
|
||||
totem.func(cli, shaman, shaman, target, messages["random_totem_prefix"]) # XXX: Old API
|
||||
else:
|
||||
LASTGIVEN[shaman] = None
|
||||
elif shaman not in SHAMANS:
|
||||
@ -594,7 +594,7 @@ def on_myrole(evt, cli, var, nick):
|
||||
evt.data["messages"].append(messages["totem_simple"].format(TOTEMS[nick]))
|
||||
|
||||
@event_listener("revealroles_role")
|
||||
def on_revealroles(evt, cli, var, nickname, role):
|
||||
def on_revealroles(evt, var, wrapper, nickname, role):
|
||||
if role in var.TOTEM_ORDER and nickname in TOTEMS:
|
||||
if nickname in SHAMANS:
|
||||
evt.data["special_case"].append("giving {0} totem to {1}".format(TOTEMS[nickname], SHAMANS[nickname][0]))
|
||||
|
@ -7,8 +7,8 @@ from collections import defaultdict
|
||||
import botconfig
|
||||
import src.settings as var
|
||||
from src.utilities import *
|
||||
from src import debuglog, errlog, plog
|
||||
from src.decorators import cmd, event_listener
|
||||
from src import channels, users, debuglog, errlog, plog
|
||||
from src.decorators import command, event_listener
|
||||
from src.messages import messages
|
||||
from src.events import Event
|
||||
|
||||
|
@ -4,79 +4,79 @@ from collections import defaultdict
|
||||
|
||||
import src.settings as var
|
||||
from src.utilities import *
|
||||
from src import debuglog, errlog, plog
|
||||
from src.decorators import cmd, event_listener
|
||||
from src import channels, users, debuglog, errlog, plog
|
||||
from src.decorators import command, event_listener
|
||||
from src.messages import messages
|
||||
from src.events import Event
|
||||
|
||||
KILLS = {} # type: Dict[str, str]
|
||||
GHOSTS = {} # type: Dict[str, str]
|
||||
GHOSTS = {} # type: Dict[users.User, str]
|
||||
|
||||
# temporary holding variable, only non-empty during transition_day
|
||||
# as such, no need to track nick changes, etc. with it
|
||||
drivenoff = {} # type: Dict[str, str]
|
||||
|
||||
@cmd("kill", chan=False, pm=True, playing=False, silenced=True, phases=("night",), nicks=GHOSTS)
|
||||
def vg_kill(cli, nick, chan, rest):
|
||||
@command("kill", chan=False, pm=True, playing=False, silenced=True, phases=("night",), users=GHOSTS)
|
||||
def vg_kill(var, wrapper, message):
|
||||
"""Take revenge on someone each night after you die."""
|
||||
if GHOSTS[nick][0] == "!":
|
||||
if GHOSTS[wrapper.source][0] == "!":
|
||||
return
|
||||
|
||||
victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
|
||||
victim = get_victim(wrapper.source.client, wrapper.source.nick, re.split(" +", message)[0], False)
|
||||
if not victim:
|
||||
return
|
||||
|
||||
if victim == nick:
|
||||
pm(cli, nick, messages["player_dead"])
|
||||
if victim == wrapper.source.nick:
|
||||
wrapper.pm(messages["player_dead"])
|
||||
return
|
||||
|
||||
wolves = list_players(var.WOLFTEAM_ROLES)
|
||||
if GHOSTS[nick] == "wolves" and victim not in wolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_wolf"])
|
||||
if GHOSTS[wrapper.source] == "wolves" and victim not in wolves:
|
||||
wrapper.pm(messages["vengeful_ghost_wolf"])
|
||||
return
|
||||
elif GHOSTS[nick] == "villagers" and victim in wolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_villager"])
|
||||
elif GHOSTS[wrapper.source] == "villagers" and victim in wolves:
|
||||
wrapper.pm(messages["vengeful_ghost_villager"])
|
||||
return
|
||||
|
||||
orig = victim
|
||||
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": False})
|
||||
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
||||
evt.dispatch(wrapper.source.client, var, "kill", wrapper.source.nick, victim, frozenset({"detrimental"}))
|
||||
if evt.prevent_default:
|
||||
return
|
||||
victim = evt.data["target"]
|
||||
|
||||
KILLS[nick] = victim
|
||||
KILLS[wrapper.source.nick] = victim
|
||||
|
||||
msg = messages["wolf_target"].format(orig)
|
||||
pm(cli, nick, messages["player"].format(msg))
|
||||
wrapper.pm(messages["player"].format(msg))
|
||||
|
||||
debuglog("{0} ({1}) KILL: {2} ({3})".format(nick, get_role(nick), victim, get_role(victim)))
|
||||
chk_nightdone(cli)
|
||||
debuglog("{0} ({1}) KILL: {2} ({3})".format(wrapper.source.nick, get_role(wrapper.source.nick), victim, get_role(victim)))
|
||||
chk_nightdone(wrapper.source.client)
|
||||
|
||||
@cmd("retract", "r", chan=False, pm=True, playing=False, phases=("night",))
|
||||
def vg_retract(cli, nick, chan, rest):
|
||||
@command("retract", "r", chan=False, pm=True, playing=False, phases=("night",))
|
||||
def vg_retract(var, wrapper, message):
|
||||
"""Removes a vengeful ghost's kill selection."""
|
||||
if nick not in GHOSTS:
|
||||
if wrapper.source not in GHOSTS:
|
||||
return
|
||||
if nick in KILLS:
|
||||
del KILLS[nick]
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
if wrapper.source.nick in KILLS:
|
||||
del KILLS[wrapper.source.nick]
|
||||
wrapper.pm(messages["retracted_kill"])
|
||||
|
||||
@event_listener("list_participants")
|
||||
def on_list_participants(evt, var):
|
||||
evt.data["pl"].extend([p for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
evt.data["pl"].extend([p.nick for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
evt.data["pl"].extend([p for p in drivenoff])
|
||||
|
||||
@event_listener("player_win", priority=1)
|
||||
def on_player_win(evt, cli, var, nick, role, winner, survived):
|
||||
def on_player_win(evt, var, user, role, winner, survived):
|
||||
# alive VG winning is handled in villager.py
|
||||
# extending VG to work with new teams can be done by registering
|
||||
# a listener at priority > 1, importing src.roles.vengefulghost,
|
||||
# and checking if the nick is in GHOSTS.
|
||||
if nick in GHOSTS:
|
||||
# and checking if the user is in GHOSTS.
|
||||
if user in GHOSTS:
|
||||
evt.data["special"].append("vg activated")
|
||||
against = GHOSTS[nick]
|
||||
if GHOSTS[nick][0] == "!":
|
||||
against = GHOSTS[user]
|
||||
if against[0] == "!":
|
||||
evt.data["special"].append("vg driven off")
|
||||
against = against[1:]
|
||||
if against == "villagers" and winner == "wolves":
|
||||
@ -97,14 +97,15 @@ def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||
del KILLS[h]
|
||||
# extending VG to work with new teams can be done by registering a listener
|
||||
# at priority < 6, importing src.roles.vengefulghost, and setting
|
||||
# GHOSTS[nick] to something; if that is done then this logic is not run.
|
||||
if death_triggers and nickrole == "vengeful ghost" and nick not in GHOSTS:
|
||||
# GHOSTS[user] to something; if that is done then this logic is not run.
|
||||
user = users._get(nick) # FIXME
|
||||
if death_triggers and nickrole == "vengeful ghost" and user not in GHOSTS:
|
||||
if evt.params.killer_role in var.WOLFTEAM_ROLES:
|
||||
GHOSTS[nick] = "wolves"
|
||||
GHOSTS[user] = "wolves"
|
||||
else:
|
||||
GHOSTS[nick] = "villagers"
|
||||
pm(cli, nick, messages["vengeful_turn"].format(GHOSTS[nick]))
|
||||
debuglog(nick, "(vengeful ghost) TRIGGER", GHOSTS[nick])
|
||||
GHOSTS[user] = "villagers"
|
||||
user.send(messages["vengeful_turn"].format(GHOSTS[user]))
|
||||
debuglog(nick, "(vengeful ghost) TRIGGER", GHOSTS[user])
|
||||
|
||||
@event_listener("rename_player")
|
||||
def on_rename(evt, cli, var, prefix, nick):
|
||||
@ -118,8 +119,6 @@ def on_rename(evt, cli, var, prefix, nick):
|
||||
KILLS.update(kvp)
|
||||
if prefix in KILLS:
|
||||
del KILLS[prefix]
|
||||
if prefix in GHOSTS:
|
||||
GHOSTS[nick] = GHOSTS.pop(prefix)
|
||||
|
||||
@event_listener("night_acted")
|
||||
def on_acted(evt, cli, var, nick, sender):
|
||||
@ -132,22 +131,22 @@ def on_transition_day_begin(evt, cli, var):
|
||||
wolves = set(list_players(var.WOLFTEAM_ROLES))
|
||||
villagers = set(list_players()) - wolves
|
||||
for ghost, target in GHOSTS.items():
|
||||
if target[0] == "!" or ghost in var.SILENCED:
|
||||
if target[0] == "!" or ghost.nick in var.SILENCED:
|
||||
continue
|
||||
if ghost not in KILLS:
|
||||
if ghost.nick not in KILLS:
|
||||
choice = set()
|
||||
if target == "wolves":
|
||||
choice = wolves.copy()
|
||||
elif target == "villagers":
|
||||
choice = villagers.copy()
|
||||
evt = Event("vg_kill", {"pl": choice})
|
||||
evt.dispatch(cli, var, ghost, target)
|
||||
evt.dispatch(var, ghost, target)
|
||||
choice = evt.data["pl"]
|
||||
# roll this into the above event once succubus is split off
|
||||
if ghost in var.ENTRANCED:
|
||||
if ghost.nick in var.ENTRANCED:
|
||||
choice -= var.ROLES["succubus"]
|
||||
if choice:
|
||||
KILLS[ghost] = random.choice(list(choice))
|
||||
KILLS[ghost.nick] = random.choice(list(choice))
|
||||
|
||||
@event_listener("transition_day", priority=2)
|
||||
def on_transition_day(evt, cli, var):
|
||||
@ -159,35 +158,35 @@ def on_transition_day(evt, cli, var):
|
||||
@event_listener("transition_day", priority=3.01)
|
||||
def on_transition_day3(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
if GHOSTS[k] == "villagers":
|
||||
if GHOSTS[users._get(k)] == "villagers":
|
||||
evt.data["killers"][d].remove(k)
|
||||
evt.data["killers"][d].insert(0, k)
|
||||
|
||||
@event_listener("transition_day", priority=6.01)
|
||||
def on_transition_day6(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
if GHOSTS[k] == "villagers" and k in evt.data["killers"][d]:
|
||||
if GHOSTS[users._get(k)] == "villagers" and k in evt.data["killers"][d]:
|
||||
evt.data["killers"][d].remove(k)
|
||||
evt.data["killers"][d].insert(0, k)
|
||||
# important, otherwise our del_player listener messages the vg
|
||||
del KILLS[k]
|
||||
|
||||
@event_listener("retribution_kill")
|
||||
@event_listener("retribution_kill") # FIXME: This function, and all of the event
|
||||
def on_retribution_kill(evt, cli, var, victim, orig_target):
|
||||
t = evt.data["target"]
|
||||
if t in GHOSTS:
|
||||
drivenoff[t] = GHOSTS[t]
|
||||
GHOSTS[t] = "!" + GHOSTS[t]
|
||||
if users._get(t) in GHOSTS:
|
||||
drivenoff[t] = GHOSTS[users._get(t)]
|
||||
GHOSTS[users._get(t)] = "!" + GHOSTS[users._get(t)]
|
||||
evt.data["message"].append(messages["totem_banish"].format(victim, t))
|
||||
evt.data["target"] = None
|
||||
|
||||
@event_listener("get_participant_role")
|
||||
def on_get_participant_role(evt, var, nick):
|
||||
if nick in GHOSTS:
|
||||
if users._get(nick) in GHOSTS: # FIXME
|
||||
if nick in drivenoff:
|
||||
against = drivenoff[nick]
|
||||
else:
|
||||
against = GHOSTS[nick]
|
||||
against = GHOSTS[users._get(nick)]
|
||||
if against == "villagers":
|
||||
evt.data["role"] = "wolf"
|
||||
elif against == "wolves":
|
||||
@ -196,7 +195,7 @@ def on_get_participant_role(evt, var, nick):
|
||||
@event_listener("chk_nightdone")
|
||||
def on_chk_nightdone(evt, cli, var):
|
||||
evt.data["actedcount"] += len(KILLS)
|
||||
evt.data["nightroles"].extend([p for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
evt.data["nightroles"].extend([p.nick for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
|
||||
@event_listener("transition_night_end", priority=2)
|
||||
def on_transition_night_end(evt, cli, var):
|
||||
@ -215,27 +214,28 @@ def on_transition_night_end(evt, cli, var):
|
||||
|
||||
random.shuffle(pl)
|
||||
|
||||
if v_ghost in var.PLAYERS and not is_user_simple(v_ghost):
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_notify"].format(who))
|
||||
if not v_ghost.prefers_simple():
|
||||
v_ghost.send(messages["vengeful_ghost_notify"].format(who))
|
||||
else:
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_simple"])
|
||||
pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl))
|
||||
debuglog("GHOST: {0} (target: {1}) - players: {2}".format(v_ghost, who, ", ".join(pl)))
|
||||
v_ghost.send(messages["vengeful_ghost_simple"])
|
||||
v_ghost.send(who.capitalize() + ": " + ", ".join(pl))
|
||||
debuglog("GHOST: {0} (target: {1}) - players: {2}".format(v_ghost.nick, who, ", ".join(pl)))
|
||||
|
||||
@event_listener("myrole")
|
||||
def on_myrole(evt, cli, var, nick):
|
||||
if nick in GHOSTS:
|
||||
user = users._get(nick)
|
||||
if user in GHOSTS:
|
||||
evt.prevent_default = True
|
||||
if GHOSTS[nick][0] != "!":
|
||||
pm(cli, nick, messages["vengeful_role"].format(GHOSTS[nick]))
|
||||
if GHOSTS[user][0] != "!":
|
||||
user.send(messages["vengeful_role"].format(GHOSTS[user]))
|
||||
|
||||
@event_listener("revealroles")
|
||||
def on_revealroles(evt, cli, var):
|
||||
def on_revealroles(evt, var, wrapper):
|
||||
if GHOSTS:
|
||||
glist = []
|
||||
for ghost, team in GHOSTS.items():
|
||||
dead = "driven away, " if team[0] == "!" else ""
|
||||
glist.append("{0} ({1}against {2})".format(ghost, dead, team.lstrip("!")))
|
||||
glist.append("{0} ({1}against {2})".format(ghost.nick, dead, team.lstrip("!")))
|
||||
evt.data["output"].append("\u0002dead vengeful ghost\u0002: {0}".format(", ".join(glist)))
|
||||
|
||||
@event_listener("begin_day")
|
||||
|
@ -33,7 +33,7 @@ def on_transition_night_end(evt, cli, var):
|
||||
# No listeners should register before this one
|
||||
# This sets up the initial state, based on village/wolfteam/neutral affiliation
|
||||
@event_listener("player_win", priority=0)
|
||||
def on_player_win(evt, cli, var, nick, role, winner, survived):
|
||||
def on_player_win(evt, var, user, role, winner, survived):
|
||||
# init won/iwon to False
|
||||
evt.data["won"] = False
|
||||
evt.data["iwon"] = False
|
||||
|
@ -145,7 +145,7 @@ def on_transition_night_end(evt, cli, var):
|
||||
pm(cli, child, messages["child_simple"])
|
||||
|
||||
@event_listener("revealroles_role")
|
||||
def on_revealroles_role(evt, cli, var, nick, role):
|
||||
def on_revealroles_role(evt, var, wrapper, nick, role):
|
||||
if role == "wild child":
|
||||
if nick in IDOLS:
|
||||
evt.data["special_case"].append("picked {0} as idol".format(IDOLS[nick]))
|
||||
|
14
src/users.py
14
src/users.py
@ -104,8 +104,14 @@ def _add(cli, *, nick, ident=None, host=None, realname=None, account=None):
|
||||
|
||||
new = cls(cli, nick, ident, host, realname, account)
|
||||
|
||||
if new is not Bot and new.ident is not None and new.host is not None:
|
||||
_users.add(new)
|
||||
if new is not Bot:
|
||||
try:
|
||||
hash(new)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
_users.add(new)
|
||||
|
||||
return new
|
||||
|
||||
def add(nick, **blah): # backwards-compatible API
|
||||
@ -246,7 +252,7 @@ class User(IRCContext):
|
||||
return True
|
||||
|
||||
for hostmask in hosts:
|
||||
if match_hostmask(hostmask, self.nick, self.ident, self.host):
|
||||
if self.match_hostmask(hostmask):
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -268,7 +274,7 @@ class User(IRCContext):
|
||||
return True
|
||||
|
||||
for hostmask in hosts:
|
||||
if match_hostmask(hostmask, self.nick, self.ident, self.host):
|
||||
if self.match_hostmask(hostmask):
|
||||
return True
|
||||
except AttributeError:
|
||||
pass
|
||||
|
438
src/wolfgame.py
438
src/wolfgame.py
@ -46,10 +46,11 @@ import botconfig
|
||||
import src
|
||||
import src.settings as var
|
||||
from src.utilities import *
|
||||
from src import db, decorators, events, channels, users, hooks, logger, proxy, debuglog, errlog, plog
|
||||
from src.decorators import cmd, hook, handle_error, event_listener, COMMANDS
|
||||
from src import db, events, channels, users, hooks, logger, proxy, debuglog, errlog, plog
|
||||
from src.decorators import command, cmd, hook, handle_error, event_listener, COMMANDS
|
||||
from src.messages import messages
|
||||
from src.warnings import *
|
||||
from src.context import IRCContext
|
||||
|
||||
# done this way so that events is accessible in !eval (useful for debugging)
|
||||
Event = events.Event
|
||||
@ -135,12 +136,12 @@ def connect_callback():
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
if signum in (signal.SIGINT, signal.SIGTERM):
|
||||
forced_exit.func(cli, "<console>", botconfig.CHANNEL, "")
|
||||
forced_exit.func(cli, "<console>", botconfig.CHANNEL, "") # XXX: Old API
|
||||
elif signum == SIGUSR1:
|
||||
restart_program.func(cli, "<console>", botconfig.CHANNEL, "")
|
||||
restart_program.func(cli, "<console>", botconfig.CHANNEL, "") # XXX: Old API
|
||||
elif signum == SIGUSR2:
|
||||
plog("Scheduling aftergame restart")
|
||||
aftergame.func(cli, "<console>", botconfig.CHANNEL, "frestart")
|
||||
aftergame.func(cli, "<console>", botconfig.CHANNEL, "frestart") # XXX: Old API
|
||||
|
||||
signal.signal(signal.SIGINT, sighandler)
|
||||
signal.signal(signal.SIGTERM, sighandler)
|
||||
@ -360,7 +361,7 @@ def refreshdb(cli, nick, chan, rest):
|
||||
reply(cli, nick, chan, "Done.")
|
||||
|
||||
@cmd("die", "bye", "fdie", "fbye", flag="D", pm=True)
|
||||
def forced_exit(cli, nick, chan, rest):
|
||||
def forced_exit(cli, nick, chan, rest): # XXX: sighandler (top of file) also needs updating alongside this one
|
||||
"""Forces the bot to close."""
|
||||
|
||||
args = rest.split()
|
||||
@ -413,7 +414,7 @@ def _restart_program(cli, mode=None):
|
||||
|
||||
|
||||
@cmd("restart", "frestart", flag="D", pm=True)
|
||||
def restart_program(cli, nick, chan, rest):
|
||||
def restart_program(cli, nick, chan, rest): # XXX: sighandler (top of file) also needs updating alongside this one
|
||||
"""Restarts the bot."""
|
||||
|
||||
args = rest.split()
|
||||
@ -791,7 +792,7 @@ def toggle_altpinged_status(nick, value, old=None):
|
||||
var.PING_IF_NUMS[old].discard(hostmask)
|
||||
|
||||
@handle_error
|
||||
def join_timer_handler(cli):
|
||||
def join_timer_handler():
|
||||
with var.WARNING_LOCK:
|
||||
var.PINGING_IFS = True
|
||||
to_ping = []
|
||||
@ -830,7 +831,7 @@ def join_timer_handler(cli):
|
||||
var.PINGING_IFS = False
|
||||
return
|
||||
|
||||
@hook("whoreply", hookid=387)
|
||||
@hook("whoreply", hookid=387) # FIXME: Use events
|
||||
def ping_altpingers_noacc(cli, bot_server, bot_nick, chan, ident, host, server, nick, status, hopcount_gecos):
|
||||
if ("G" in status or is_user_stasised(nick) or not var.PINGING_IFS or
|
||||
nick == bot_nick or nick in pl):
|
||||
@ -865,7 +866,7 @@ def join_timer_handler(cli):
|
||||
var.PINGED_ALREADY.add(hostmask)
|
||||
|
||||
@hook("endofwho", hookid=387)
|
||||
def fetch_altpingers(*stuff):
|
||||
def fetch_altpingers(cli, *stuff):
|
||||
# fun fact: if someone joined 10 seconds after someone else, the bot would break.
|
||||
# effectively, the join would delete join_pinger from var.TIMERS and this function
|
||||
# here would be reached before it was created again, thus erroring and crashing.
|
||||
@ -882,11 +883,7 @@ def join_timer_handler(cli):
|
||||
|
||||
cli.msg(botconfig.CHANNEL, msg)
|
||||
|
||||
# FIXME
|
||||
if not var.DISABLE_ACCOUNTS:
|
||||
cli.who(botconfig.CHANNEL, "%tcuihsnfdlar,")
|
||||
else:
|
||||
cli.who(botconfig.CHANNEL)
|
||||
channels.Main.who()
|
||||
|
||||
def get_deadchat_pref(nick):
|
||||
if users.exists(nick):
|
||||
@ -991,8 +988,8 @@ def deadchat_pref(cli, nick, chan, rest):
|
||||
|
||||
reply(cli, nick, chan, msg, private=True)
|
||||
|
||||
@cmd("join", "j", pm=True)
|
||||
def join(cli, nick, chan, rest):
|
||||
@command("join", "j", pm=True)
|
||||
def join(var, wrapper, message):
|
||||
"""Either starts a new game of Werewolf or joins an existing game that has not started yet."""
|
||||
# keep this and the event in fjoin() in sync
|
||||
evt = Event("join", {
|
||||
@ -1000,72 +997,57 @@ def join(cli, nick, chan, rest):
|
||||
"join_deadchat": join_deadchat,
|
||||
"vote_gamemode": vote_gamemode
|
||||
})
|
||||
if not evt.dispatch(cli, var, nick, chan, rest, forced=False):
|
||||
if not evt.dispatch(var, wrapper, message, forced=False):
|
||||
return
|
||||
if var.PHASE in ("none", "join"):
|
||||
if chan == nick:
|
||||
if wrapper.private:
|
||||
return
|
||||
if var.ACCOUNTS_ONLY:
|
||||
if users.exists(nick) and (not users.get(nick).account or users.get(nick).account == "*"):
|
||||
cli.notice(nick, messages["not_logged_in"])
|
||||
if users._get(nick).account is None: # FIXME
|
||||
wrapper.pm(messages["not_logged_in"])
|
||||
return
|
||||
if evt.data["join_player"](cli, nick, chan) and rest:
|
||||
evt.data["vote_gamemode"](cli, nick, chan, rest.lower().split()[0], False)
|
||||
if evt.data["join_player"](var, wrapper) and message:
|
||||
evt.data["vote_gamemode"](var, wrapper, message.lower().split()[0], doreply=False)
|
||||
|
||||
else: # join deadchat
|
||||
if chan == nick and nick != botconfig.NICK:
|
||||
evt.data["join_deadchat"](cli, nick)
|
||||
if wrapper.private and wrapper.source is not wrapper.target:
|
||||
evt.data["join_deadchat"](var, wrapper)
|
||||
|
||||
def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
|
||||
def join_player(var, wrapper, who=None, forced=False, *, sanity=True):
|
||||
if who is None:
|
||||
who = player
|
||||
who = wrapper.source
|
||||
|
||||
pl = list_players()
|
||||
if chan != botconfig.CHANNEL:
|
||||
if wrapper.target is not channels.Main:
|
||||
return False
|
||||
|
||||
if users.exists(player):
|
||||
ident = irc_lower(users.get(player).ident)
|
||||
host = users.get(player).host.lower()
|
||||
acc = irc_lower(users.get(player).account)
|
||||
hostmask = player + "!" + ident + "@" + host
|
||||
elif is_fake_nick(player) and botconfig.DEBUG_MODE:
|
||||
# fakenick
|
||||
ident = None
|
||||
host = None
|
||||
acc = None
|
||||
hostmask = None
|
||||
else:
|
||||
return False # Not normal
|
||||
if not acc or acc == "*" or var.DISABLE_ACCOUNTS:
|
||||
acc = None
|
||||
|
||||
stasis = is_user_stasised(player)
|
||||
stasis = wrapper.source.stasis_count()
|
||||
|
||||
if stasis > 0:
|
||||
if forced and stasis == 1:
|
||||
decrement_stasis(player)
|
||||
decrement_stasis(wrapper.source.nick)
|
||||
else:
|
||||
cli.notice(who, messages["stasis"].format(
|
||||
"you are" if player == who else player + " is", stasis,
|
||||
"s" if stasis != 1 else ""))
|
||||
who.send(messages["stasis"].format(
|
||||
"you are" if wrapper.source is who else wrapper.source.nick + " is", stasis,
|
||||
"s" if stasis != 1 else ""), notice=True)
|
||||
return False
|
||||
|
||||
temp = wrapper.source.lower()
|
||||
|
||||
# don't check unacked warnings on fjoin
|
||||
if who == player and db.has_unacknowledged_warnings(acc, hostmask):
|
||||
cli.notice(player, messages["warn_unacked"])
|
||||
if wrapper.source is who and db.has_unacknowledged_warnings(temp.account, temp.rawnick):
|
||||
wrapper.pm(messages["warn_unacked"])
|
||||
return False
|
||||
|
||||
cmodes = [("+v", player)]
|
||||
cmodes = [("+v", wrapper.source.nick)]
|
||||
if var.PHASE == "none":
|
||||
if var.AUTO_TOGGLE_MODES and users.exists(player) and users.get(player).modes:
|
||||
for mode in users.get(player).modes:
|
||||
cmodes.append(("-"+mode, player))
|
||||
users.get(player).moded.update(users.get(player).modes)
|
||||
users.get(player).modes = set()
|
||||
mass_mode(cli, cmodes, [])
|
||||
var.ROLES["person"].add(player)
|
||||
var.ALL_PLAYERS.append(player)
|
||||
if var.AUTO_TOGGLE_MODES and users.get(player).modes: # FIXME: Need to properly handle mode changes (whole block)
|
||||
for mode in users.get(wrapper.source.nick).modes:
|
||||
cmodes.append(("-"+mode, wrapper.source.nick))
|
||||
users.get(wrapper.source.nick).moded.update(users.get(wrapper.source.nick).modes)
|
||||
users.get(wrapper.source.nick).modes.clear()
|
||||
var.ROLES["person"].add(wrapper.source.nick) # FIXME: Need to store Users, not nicks
|
||||
var.ALL_PLAYERS.append(wrapper.source.nick)
|
||||
var.PHASE = "join"
|
||||
with var.WAIT_TB_LOCK:
|
||||
var.WAIT_TB_TOKENS = var.WAIT_TB_INIT
|
||||
@ -1073,12 +1055,12 @@ def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
|
||||
var.GAME_ID = time.time()
|
||||
var.PINGED_ALREADY_ACCS = set()
|
||||
var.PINGED_ALREADY = set()
|
||||
if host:
|
||||
var.JOINED_THIS_GAME.add(ident + "@" + host)
|
||||
if acc:
|
||||
var.JOINED_THIS_GAME_ACCS.add(acc)
|
||||
if wrapper.source.userhost:
|
||||
var.JOINED_THIS_GAME.add(wrapper.source.userhost)
|
||||
if wrapper.source.account:
|
||||
var.JOINED_THIS_GAME_ACCS.add(wrapper.source.account)
|
||||
var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT)
|
||||
cli.msg(chan, messages["new_game"].format(player, botconfig.CMD_CHAR))
|
||||
wrapper.send(messages["new_game"].format(wrapper.source.nick, botconfig.CMD_CHAR))
|
||||
|
||||
# Set join timer
|
||||
if var.JOIN_TIME_LIMIT > 0:
|
||||
@ -1087,52 +1069,50 @@ def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
elif player in pl:
|
||||
cli.notice(who, messages["already_playing"].format("You" if who == player else "They"))
|
||||
elif wrapper.source.nick in pl: # FIXME: To fix when everything returns Users
|
||||
who.send(messages["already_playing"].format("You" if who is wrapper.source else "They"), notice=True)
|
||||
# if we're not doing insane stuff, return True so that one can use !join to vote for a game mode
|
||||
# even if they are already joined. If we ARE doing insane stuff, return False to indicate that
|
||||
# the player was not successfully joined by this call.
|
||||
return sanity
|
||||
elif len(pl) >= var.MAX_PLAYERS:
|
||||
cli.notice(who, messages["too_many_players"])
|
||||
who.send(messages["too_many_players"], notice=True)
|
||||
return False
|
||||
elif sanity and var.PHASE != "join":
|
||||
cli.notice(who, messages["game_already_running"])
|
||||
who.send(messages["game_already_running"], notice=True)
|
||||
return False
|
||||
else:
|
||||
if acc is not None and not botconfig.DEBUG_MODE:
|
||||
for user in pl:
|
||||
if irc_lower(users.get(user).account) == acc:
|
||||
if not botconfig.DEBUG_MODE:
|
||||
for nick in pl:
|
||||
if users._get(nick).lower().account == temp.account: # FIXME
|
||||
msg = messages["account_already_joined"]
|
||||
if who == player:
|
||||
cli.notice(who, msg.format(user, "your", messages["join_swap_instead"].format(botconfig.CMD_CHAR)))
|
||||
if who is wrapper.source:
|
||||
who.send(msg.format(user, "your", messages["join_swap_instead"].format(botconfig.CMD_CHAR)), notice=True)
|
||||
else:
|
||||
cli.notice(who, msg.format(user, "their", ""))
|
||||
who.send(msg.format(user, "their", ""), notice=True)
|
||||
return
|
||||
|
||||
var.ALL_PLAYERS.append(player)
|
||||
if not is_fake_nick(player) or not botconfig.DEBUG_MODE:
|
||||
if var.AUTO_TOGGLE_MODES and users.get(player).modes:
|
||||
for mode in var.USERS[player]["modes"]:
|
||||
cmodes.append(("-"+mode, player))
|
||||
users.get(player).moded.update(users.get(player).modes)
|
||||
users.get(player).modes = set()
|
||||
mass_mode(cli, cmodes, [])
|
||||
cli.msg(chan, messages["player_joined"].format(player, len(pl) + 1))
|
||||
var.ALL_PLAYERS.append(wrapper.source.nick)
|
||||
if not wrapper.source.is_fake or not botconfig.DEBUG_MODE:
|
||||
if var.AUTO_TOGGLE_MODES and users.get(wrapper.source.nick).modes:
|
||||
for mode in users.get(wrapper.source.nick).modes:
|
||||
cmodes.append(("-"+mode, wrapper.source.nick))
|
||||
users.get(wrapper.source.nick).moded.update(users.get(wrapper.source.nick).modes)
|
||||
users.get(wrapper.source.nick).modes.clear()
|
||||
wrapper.send(messages["player_joined"].format(wrapper.source.nick, len(pl) + 1))
|
||||
if not sanity:
|
||||
# Abandon Hope All Ye Who Enter Here
|
||||
leave_deadchat(cli, player)
|
||||
var.SPECTATING_DEADCHAT.discard(player)
|
||||
var.SPECTATING_WOLFCHAT.discard(player)
|
||||
leave_deadchat(wrapper.source.client, wrapper.source.nick)
|
||||
var.SPECTATING_DEADCHAT.discard(wrapper.source.nick)
|
||||
var.SPECTATING_WOLFCHAT.discard(wrapper.source.nick)
|
||||
return True
|
||||
var.ROLES["person"].add(player)
|
||||
if not is_fake_nick(player):
|
||||
hostmask = ident + "@" + host
|
||||
if hostmask not in var.JOINED_THIS_GAME and (not acc or acc not in var.JOINED_THIS_GAME_ACCS):
|
||||
var.ROLES["person"].add(wrapper.source.nick)
|
||||
if not wrapper.source.is_fake:
|
||||
if wrapper.source.userhost not in var.JOINED_THIS_GAME and wrapper.source.account not in var.JOINED_THIS_GAME_ACCS:
|
||||
# make sure this only happens once
|
||||
var.JOINED_THIS_GAME.add(hostmask)
|
||||
if acc:
|
||||
var.JOINED_THIS_GAME_ACCS.add(acc)
|
||||
var.JOINED_THIS_GAME.add(wrapper.source.userhost)
|
||||
if wrapper.source.account:
|
||||
var.JOINED_THIS_GAME_ACCS.add(wrapper.source.account)
|
||||
now = datetime.now()
|
||||
|
||||
# add var.EXTRA_WAIT_JOIN to wait time
|
||||
@ -1154,11 +1134,13 @@ def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
|
||||
if "join_pinger" in var.TIMERS:
|
||||
var.TIMERS["join_pinger"][0].cancel()
|
||||
|
||||
t = threading.Timer(10, join_timer_handler, (cli,))
|
||||
t = threading.Timer(10, join_timer_handler)
|
||||
var.TIMERS["join_pinger"] = (t, time.time(), 10)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
channels.Main.mode(*cmodes)
|
||||
|
||||
return True
|
||||
|
||||
@handle_error
|
||||
@ -1179,8 +1161,8 @@ def kill_join(cli, chan):
|
||||
var.AFTER_FLASTGAME = None
|
||||
|
||||
|
||||
@cmd("fjoin", flag="A")
|
||||
def fjoin(cli, nick, chan, rest):
|
||||
@command("fjoin", flag="A")
|
||||
def fjoin(var, wrapper, message):
|
||||
"""Forces someone to join a game."""
|
||||
# keep this and the event in def join() in sync
|
||||
evt = Event("join", {
|
||||
@ -1188,24 +1170,26 @@ def fjoin(cli, nick, chan, rest):
|
||||
"join_deadchat": join_deadchat,
|
||||
"vote_gamemode": vote_gamemode
|
||||
})
|
||||
if not evt.dispatch(cli, var, nick, chan, rest, forced=True):
|
||||
if not evt.dispatch(var, wrapper, message, forced=True):
|
||||
return
|
||||
noticed = False
|
||||
fake = False
|
||||
if not rest.strip():
|
||||
evt.data["join_player"](cli, nick, chan, forced=True)
|
||||
if not message.strip():
|
||||
evt.data["join_player"](var, wrapper, forced=True)
|
||||
|
||||
for tojoin in re.split(" +",rest):
|
||||
for tojoin in re.split(" +", message):
|
||||
tojoin = tojoin.strip()
|
||||
if "-" in tojoin:
|
||||
first, hyphen, last = tojoin.partition("-")
|
||||
if first.isdigit() and last.isdigit():
|
||||
if int(last)+1 - int(first) > var.MAX_PLAYERS - len(list_players()):
|
||||
cli.msg(chan, messages["too_many_players_to_join"].format(nick))
|
||||
wrapper.send(messages["too_many_players_to_join"].format(wrapper.source.nick))
|
||||
break
|
||||
fake = True
|
||||
for i in range(int(first), int(last)+1):
|
||||
evt.data["join_player"](cli, str(i), chan, forced=True, who=nick)
|
||||
user = users._add(wrapper.source.client, nick=str(i)) # FIXME
|
||||
channels.Dummy.users.add(user) # keep a strong reference to fake users (this will be removed eventually)
|
||||
evt.data["join_player"](var, type(wrapper)(user, wrapper.target), forced=True, who=wrapper.source)
|
||||
continue
|
||||
if not tojoin:
|
||||
continue
|
||||
@ -1214,23 +1198,23 @@ def fjoin(cli, nick, chan, rest):
|
||||
if tojoin.lower() not in ull or not var.USERS[ul[ull.index(tojoin.lower())]]["inchan"]:
|
||||
if not is_fake_nick(tojoin) or not botconfig.DEBUG_MODE:
|
||||
if not noticed: # important
|
||||
cli.msg(chan, nick+messages["fjoin_in_chan"])
|
||||
wrapper.send(wrapper.source.nick+messages["fjoin_in_chan"])
|
||||
noticed = True
|
||||
continue
|
||||
if not is_fake_nick(tojoin):
|
||||
tojoin = ul[ull.index(tojoin.lower())].strip()
|
||||
if not botconfig.DEBUG_MODE and var.ACCOUNTS_ONLY:
|
||||
if not users.get(tojoin).account or users.get(tojoin).account == "*":
|
||||
cli.notice(nick, messages["account_not_logged_in"].format(tojoin))
|
||||
wrapper.pm(messages["account_not_logged_in"].format(tojoin))
|
||||
return
|
||||
elif botconfig.DEBUG_MODE:
|
||||
fake = True
|
||||
if tojoin != botconfig.NICK:
|
||||
evt.data["join_player"](cli, tojoin, chan, forced=True, who=nick)
|
||||
if tojoin != users.Bot.nick:
|
||||
evt.data["join_player"](var, type(wrapper)(users._add(wrapper.source.client, nick=tojoin), wrapper.target), forced=True, who=wrapper.source)
|
||||
else:
|
||||
cli.notice(nick, messages["not_allowed"])
|
||||
wrapper.pm(messages["not_allowed"])
|
||||
if fake:
|
||||
cli.msg(chan, messages["fjoin_success"].format(nick, len(list_players())))
|
||||
wrapper.send(messages["fjoin_success"].format(wrapper.source.nick, len(list_players())))
|
||||
|
||||
@cmd("fleave", "fquit", flag="A", pm=True, phases=("join", "day", "night"))
|
||||
def fleave(cli, nick, chan, rest):
|
||||
@ -2381,7 +2365,7 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True):
|
||||
survived = list_players()
|
||||
if not pentry["dced"]:
|
||||
evt = Event("player_win", {"won": won, "iwon": iwon, "special": pentry["special"]})
|
||||
evt.dispatch(cli, var, splr, rol, winner, splr in survived)
|
||||
evt.dispatch(var, users._get(splr), rol, winner, splr in survived) # FIXME
|
||||
won = evt.data["won"]
|
||||
iwon = evt.data["iwon"]
|
||||
# ensure that it is a) a list, and b) a copy (so it can't be mutated out from under us later)
|
||||
@ -3757,7 +3741,7 @@ def transition_day(cli, gameid=0):
|
||||
for mm in var.ROLES["matchmaker"]:
|
||||
if mm not in var.MATCHMAKERS:
|
||||
lovers = random.sample(pl, 2)
|
||||
choose.func(cli, mm, mm, lovers[0] + " " + lovers[1], sendmsg=False)
|
||||
choose.func(cli, mm, mm, lovers[0] + " " + lovers[1], sendmsg=False) # XXX: Old API
|
||||
pm(cli, mm, messages["random_matchmaker"])
|
||||
|
||||
# Reset daytime variables
|
||||
@ -4653,35 +4637,34 @@ def retract(cli, nick, chan, rest):
|
||||
else:
|
||||
cli.notice(nick, messages["pending_vote"])
|
||||
|
||||
@cmd("shoot", playing=True, silenced=True, phases=("day",))
|
||||
def shoot(cli, nick, chan, rest):
|
||||
@command("shoot", playing=True, silenced=True, phases=("day",))
|
||||
def shoot(var, wrapper, message):
|
||||
"""Use this to fire off a bullet at someone in the day if you have bullets."""
|
||||
|
||||
if chan != botconfig.CHANNEL:
|
||||
if wrapper.target is not channels.Main:
|
||||
return
|
||||
|
||||
if nick not in var.GUNNERS.keys():
|
||||
cli.notice(nick, messages["no_gun"])
|
||||
if wrapper.source.nick not in var.GUNNERS.keys():
|
||||
wrapper.pm(messages["no_gun"])
|
||||
return
|
||||
elif not var.GUNNERS.get(nick):
|
||||
cli.notice(nick, messages["no_bullets"])
|
||||
elif not var.GUNNERS.get(wrapper.source.nick):
|
||||
wrapper.pm(messages["no_bullets"])
|
||||
return
|
||||
victim = get_victim(cli, nick, re.split(" +",rest)[0], True)
|
||||
victim = get_victim(wrapper.source.client, wrapper.source.nick, re.split(" +", message)[0], True)
|
||||
if not victim:
|
||||
return
|
||||
if victim == nick:
|
||||
cli.notice(nick, messages["gunner_target_self"])
|
||||
if victim == wrapper.source.nick:
|
||||
wrapper.pm(messages["gunner_target_self"])
|
||||
return
|
||||
# get actual victim
|
||||
victim = choose_target(nick, victim)
|
||||
victim = choose_target(wrapper.source.nick, victim)
|
||||
|
||||
wolfshooter = nick in list_players(var.WOLFCHAT_ROLES)
|
||||
var.GUNNERS[nick] -= 1
|
||||
wolfshooter = wrapper.source.nick in list_players(var.WOLFCHAT_ROLES)
|
||||
var.GUNNERS[wrapper.source.nick] -= 1
|
||||
|
||||
rand = random.random()
|
||||
if nick in var.ROLES["village drunk"]:
|
||||
if wrapper.source.nick in var.ROLES["village drunk"]:
|
||||
chances = var.DRUNK_GUN_CHANCES
|
||||
elif nick in var.ROLES["sharpshooter"]:
|
||||
elif wrapper.source.nick in var.ROLES["sharpshooter"]:
|
||||
chances = var.SHARPSHOOTER_GUN_CHANCES
|
||||
else:
|
||||
chances = var.GUN_CHANCES
|
||||
@ -4698,26 +4681,26 @@ def shoot(cli, nick, chan, rest):
|
||||
if rand <= chances[0] and not (wolfshooter and wolfvictim) and not alwaysmiss:
|
||||
# didn't miss or suicide and it's not a wolf shooting another wolf
|
||||
|
||||
cli.msg(chan, messages["shoot_success"].format(nick, victim))
|
||||
wrapper.send(messages["shoot_success"].format(wrapper.source.nick, victim))
|
||||
an = "n" if victimrole.startswith(("a", "e", "i", "o", "u")) else ""
|
||||
if realrole in var.WOLF_ROLES:
|
||||
if var.ROLE_REVEAL == "on":
|
||||
cli.msg(chan, messages["gunner_victim_wolf_death"].format(victim,an, victimrole))
|
||||
wrapper.send(messages["gunner_victim_wolf_death"].format(victim,an, victimrole))
|
||||
else: # off and team
|
||||
cli.msg(chan, messages["gunner_victim_wolf_death_no_reveal"].format(victim))
|
||||
if not del_player(cli, victim, killer_role = get_role(nick)):
|
||||
wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(victim))
|
||||
if not del_player(wrapper.source.client, victim, killer_role=get_role(wrapper.source.nick)):
|
||||
return
|
||||
elif random.random() <= chances[3]:
|
||||
accident = "accidentally "
|
||||
if nick in var.ROLES["sharpshooter"]:
|
||||
if wrapper.source.nick in var.ROLES["sharpshooter"]:
|
||||
accident = "" # it's an accident if the sharpshooter DOESN'T headshot :P
|
||||
cli.msg(chan, messages["gunner_victim_villager_death"].format(victim, accident))
|
||||
wrapper.send(messages["gunner_victim_villager_death"].format(victim, accident))
|
||||
if var.ROLE_REVEAL in ("on", "team"):
|
||||
cli.msg(chan, messages["gunner_victim_role"].format(an, victimrole))
|
||||
if not del_player(cli, victim, killer_role = get_role(nick)):
|
||||
wrapper.send(messages["gunner_victim_role"].format(an, victimrole))
|
||||
if not del_player(wrapper.source.client, victim, killer_role=get_role(wrapper.source.nick)):
|
||||
return
|
||||
else:
|
||||
cli.msg(chan, messages["gunner_victim_injured"].format(victim))
|
||||
wrapper.send(messages["gunner_victim_injured"].format(victim))
|
||||
var.WOUNDED.add(victim)
|
||||
lcandidates = list(var.VOTES.keys())
|
||||
for cand in lcandidates: # remove previous vote
|
||||
@ -4726,16 +4709,16 @@ def shoot(cli, nick, chan, rest):
|
||||
if not var.VOTES.get(cand):
|
||||
del var.VOTES[cand]
|
||||
break
|
||||
chk_decision(cli)
|
||||
chk_win(cli)
|
||||
chk_decision(wrapper.source.client)
|
||||
chk_win(wrapper.source.client)
|
||||
elif rand <= chances[0] + chances[1]:
|
||||
cli.msg(chan, messages["gunner_miss"].format(nick))
|
||||
wrapper.send(messages["gunner_miss"].format(wrapper.source.nick))
|
||||
else:
|
||||
if var.ROLE_REVEAL in ("on", "team"):
|
||||
cli.msg(chan, messages["gunner_suicide"].format(nick, get_reveal_role(nick)))
|
||||
wrapper.send(messages["gunner_suicide"].format(wrapper.source.nick, get_reveal_role(wrapper.source.nick)))
|
||||
else:
|
||||
cli.msg(chan, messages["gunner_suicide_no_reveal"].format(nick))
|
||||
if not del_player(cli, nick, killer_role = "villager"): # blame explosion on villager's shoddy gun construction or something
|
||||
wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source.nick))
|
||||
if not del_player(wrapper.source.client, wrapper.source.nick, killer_role="villager"): # blame explosion on villager's shoddy gun construction or something
|
||||
return # Someone won.
|
||||
|
||||
def is_safe(nick, victim): # helper function
|
||||
@ -4788,7 +4771,7 @@ def consecrate(cli, nick, chan, rest):
|
||||
# (for example, if there was a role that could raise corpses as undead somethings, this would prevent that from working)
|
||||
# regardless if this has any actual effect or not, it still removes the priest from being able to vote
|
||||
from src.roles import vengefulghost
|
||||
if victim in vengefulghost.GHOSTS:
|
||||
if users._get(victim) in vengefulghost.GHOSTS:
|
||||
var.SILENCED.add(victim)
|
||||
|
||||
var.CONSECRATING.add(nick)
|
||||
@ -4967,7 +4950,7 @@ def hvisit(cli, nick, chan, rest):
|
||||
return
|
||||
|
||||
if nick == victim: # Staying home (same as calling pass, so call pass)
|
||||
pass_cmd.func(cli, nick, chan, "")
|
||||
pass_cmd.func(cli, nick, chan, "") # XXX: Old API
|
||||
return
|
||||
else:
|
||||
victim = choose_target(nick, victim)
|
||||
@ -5108,7 +5091,7 @@ def bite_cmd(cli, nick, chan, rest):
|
||||
|
||||
@cmd("pass", chan=False, pm=True, playing=True, phases=("night",),
|
||||
roles=("harlot", "turncoat", "warlock", "succubus"))
|
||||
def pass_cmd(cli, nick, chan, rest):
|
||||
def pass_cmd(cli, nick, chan, rest): # XXX: hvisit (3 functions above this one) also needs updating alongside this
|
||||
"""Decline to use your special power for that night."""
|
||||
nickrole = get_role(nick)
|
||||
|
||||
@ -5174,7 +5157,7 @@ def change_sides(cli, nick, chan, rest, sendmsg=True):
|
||||
|
||||
@cmd("choose", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||
@cmd("match", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||
def choose(cli, nick, chan, rest, sendmsg=True):
|
||||
def choose(cli, nick, chan, rest, sendmsg=True): # XXX: transition_day also needs updating alongside this one
|
||||
"""Select two players to fall in love. You may select yourself as one of the lovers."""
|
||||
if not var.FIRST_NIGHT:
|
||||
return
|
||||
@ -7069,7 +7052,7 @@ def myrole(cli, nick, chan, rest):
|
||||
pm(cli, nick, message)
|
||||
|
||||
@cmd("aftergame", "faftergame", flag="D", raw_nick=True, pm=True)
|
||||
def aftergame(cli, rawnick, chan, rest):
|
||||
def aftergame(cli, rawnick, chan, rest): # XXX: lastgame (just below this one) and sighandler (top of file) also need updating alongside this one
|
||||
"""Schedule a command to be run after the current game."""
|
||||
nick = parse_nick(rawnick)[0]
|
||||
if not rest.strip():
|
||||
@ -7116,7 +7099,7 @@ def flastgame(cli, rawnick, chan, rest):
|
||||
var.ADMIN_TO_PING = nick
|
||||
|
||||
if rest.strip():
|
||||
aftergame.func(cli, rawnick, botconfig.CHANNEL, rest)
|
||||
aftergame.func(cli, rawnick, botconfig.CHANNEL, rest) # XXX: Old API
|
||||
|
||||
@cmd("gamestats", "gstats", pm=True)
|
||||
def game_stats(cli, nick, chan, rest):
|
||||
@ -7159,7 +7142,7 @@ def game_stats(cli, nick, chan, rest):
|
||||
# Attempt to find game stats for the given game size
|
||||
reply(cli, nick, chan, db.get_game_stats(gamemode, gamesize))
|
||||
|
||||
@cmd("playerstats", "pstats", "player", "p", pm=True)
|
||||
@cmd("playerstats", "pstats", "player", "p", pm=True) # XXX: mystats (just after this) needs updating along this one
|
||||
def player_stats(cli, nick, chan, rest):
|
||||
"""Gets the stats for the given player and role or a list of role totals if no role is given."""
|
||||
if (chan != nick and var.LAST_PSTATS and var.PSTATS_RATE_LIMIT and
|
||||
@ -7225,49 +7208,48 @@ def my_stats(cli, nick, chan, rest):
|
||||
player_stats.func(cli, nick, chan, " ".join([nick] + rest))
|
||||
|
||||
# Called from !game and !join, used to vote for a game mode
|
||||
def vote_gamemode(cli, nick, chan, gamemode, doreply):
|
||||
def vote_gamemode(var, wrapper, gamemode, doreply):
|
||||
if var.FGAMED:
|
||||
if doreply:
|
||||
cli.notice(nick, messages["admin_forced_game"])
|
||||
wrapper.pm(messages["admin_forced_game"])
|
||||
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:
|
||||
cli.notice(nick, messages["invalid_mode_no_list"].format(gamemode))
|
||||
wrapper.pm(messages["invalid_mode_no_list"].format(gamemode))
|
||||
return
|
||||
gamemode = match
|
||||
|
||||
if gamemode != "roles" and gamemode != "villagergame" and gamemode not in var.DISABLED_GAMEMODES:
|
||||
if var.GAMEMODE_VOTES.get(nick) == gamemode:
|
||||
cli.notice(nick, messages["already_voted_game"].format(gamemode))
|
||||
if var.GAMEMODE_VOTES.get(wrapper.source.nick) == gamemode:
|
||||
wrapper.pm(messages["already_voted_game"].format(gamemode))
|
||||
else:
|
||||
var.GAMEMODE_VOTES[nick] = gamemode
|
||||
cli.msg(chan, messages["vote_game_mode"].format(nick, gamemode))
|
||||
var.GAMEMODE_VOTES[wrapper.source.nick] = gamemode
|
||||
wrapper.send(messages["vote_game_mode"].format(wrapper.source.nick, gamemode))
|
||||
else:
|
||||
if doreply:
|
||||
cli.notice(nick, messages["vote_game_fail"])
|
||||
wrapper.pm(messages["vote_game_fail"])
|
||||
|
||||
@cmd("game", playing=True, phases=("join",))
|
||||
def game(cli, nick, chan, rest):
|
||||
@command("game", playing=True, phases=("join",))
|
||||
def game(var, wrapper, message):
|
||||
"""Vote for a game mode to be picked."""
|
||||
if rest:
|
||||
vote_gamemode(cli, nick, chan, rest.lower().split()[0], True)
|
||||
if message:
|
||||
vote_gamemode(var, wrapper, message.lower().split()[0], doreply=True)
|
||||
else:
|
||||
gamemodes = ", ".join("\u0002{0}\u0002".format(gamemode) if len(list_players()) in range(var.GAME_MODES[gamemode][1],
|
||||
var.GAME_MODES[gamemode][2]+1) else gamemode for gamemode in var.GAME_MODES.keys() if gamemode != "roles" and
|
||||
gamemode != "villagergame" and gamemode not in var.DISABLED_GAMEMODES)
|
||||
cli.notice(nick, messages["no_mode_specified"] + gamemodes)
|
||||
wrapper.pm(messages["no_mode_specified"] + gamemodes)
|
||||
return
|
||||
|
||||
@cmd("games", "modes", pm=True)
|
||||
def show_modes(cli, nick, chan, rest):
|
||||
@command("games", "modes", pm=True)
|
||||
def show_modes(var, wrapper, message):
|
||||
"""Show the available game modes."""
|
||||
msg = messages["available_modes"]
|
||||
modes = "\u0002, \u0002".join(sorted(var.GAME_MODES.keys() - {"roles", "villagergame"} - var.DISABLED_GAMEMODES))
|
||||
|
||||
reply(cli, nick, chan, msg + modes + "\u0002", private=True)
|
||||
wrapper.pm("{0}{1}\u0002".format(messages["available_modes"], modes))
|
||||
|
||||
def game_help(args=""):
|
||||
return (messages["available_mode_setters_help"] +
|
||||
@ -7359,52 +7341,53 @@ def update(cli, nick, chan, rest):
|
||||
if ret:
|
||||
restart_program.caller(cli, nick, chan, "Updating bot")
|
||||
|
||||
@cmd("send", "fsend", flag="F", pm=True)
|
||||
def fsend(cli, nick, chan, rest):
|
||||
@command("send", "fsend", flag="F", pm=True)
|
||||
def fsend(var, wrapper, message):
|
||||
"""Forcibly send raw IRC commands to the server."""
|
||||
cli.send(rest)
|
||||
wrapper.source.client.send(message)
|
||||
|
||||
def _say(cli, raw_nick, rest, command, action=False):
|
||||
(nick, _, ident, host) = parse_nick(raw_nick)
|
||||
def _say(wrapper, rest, cmd, action=False):
|
||||
rest = rest.split(" ", 1)
|
||||
|
||||
if len(rest) < 2:
|
||||
pm(cli, nick, messages["fsend_usage"].format(
|
||||
botconfig.CMD_CHAR, command))
|
||||
|
||||
wrapper.pm(messages["fsend_usage"].format(botconfig.CMD_CHAR, cmd))
|
||||
return
|
||||
|
||||
(target, message) = rest
|
||||
target, message = rest
|
||||
|
||||
if not is_admin(nick, ident, host):
|
||||
if not users.exists(nick):
|
||||
pm(cli, nick, messages["wrong_channel"].format(
|
||||
botconfig.CHANNEL))
|
||||
if target.startswith(tuple(hooks.Features["CHANTYPES"])):
|
||||
targ = channels.get(target, allow_none=True)
|
||||
else:
|
||||
targ = users._get(target, allow_multiple=True) # FIXME
|
||||
if len(targ) == 1:
|
||||
targ = targ[0]
|
||||
else:
|
||||
targ = None
|
||||
|
||||
return
|
||||
|
||||
if rest[0] != botconfig.CHANNEL:
|
||||
pm(cli, nick, messages["invalid_fsend_permissions"])
|
||||
if targ is None:
|
||||
targ = IRCClient(target, wrapper.source.client)
|
||||
|
||||
if not wrapper.source.is_admin():
|
||||
if targ is not channels.Main:
|
||||
wrapper.pm(messages["invalid_fsend_permissions"])
|
||||
return
|
||||
|
||||
if action:
|
||||
message = "\u0001ACTION {0}\u0001".format(message)
|
||||
|
||||
cli.send("PRIVMSG {0} :{1}".format(target, message))
|
||||
targ.send(message, privmsg=True)
|
||||
|
||||
|
||||
@cmd("say", "fsay", flag="s", raw_nick=True, pm=True)
|
||||
def fsay(cli, raw_nick, chan, rest):
|
||||
@command("say", "fsay", flag="s", pm=True)
|
||||
def fsay(var, wrapper, message):
|
||||
"""Talk through the bot as a normal message."""
|
||||
_say(cli, raw_nick, rest, "say")
|
||||
_say(wrapper, message, "say")
|
||||
|
||||
@cmd("act", "do", "me", "fact", "fdo", "fme", flag="s", raw_nick=True, pm=True)
|
||||
def fact(cli, raw_nick, chan, rest):
|
||||
@command("act", "do", "me", "fact", "fdo", "fme", flag="s", pm=True)
|
||||
def fact(var, wrapper, message):
|
||||
"""Act through the bot as an action."""
|
||||
_say(cli, raw_nick, rest, "act", action=True)
|
||||
_say(wrapper, message, "act", action=True)
|
||||
|
||||
def can_run_restricted_cmd(nick):
|
||||
def can_run_restricted_cmd(user):
|
||||
# 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)
|
||||
@ -7414,35 +7397,34 @@ def can_run_restricted_cmd(nick):
|
||||
|
||||
pl = list_participants()
|
||||
|
||||
if nick in pl:
|
||||
if user.nick in pl: # FIXME: Need to update this once list_participants() holds User instances
|
||||
return False
|
||||
|
||||
if users.exists(nick) and users.get(nick).account in [users.get(player).account for player in pl if users.exists(player)]:
|
||||
if user.account in [users._get(player).account for player in pl]: # FIXME
|
||||
return False
|
||||
|
||||
hostmask = users.get(nick).ident + "@" + users.get(nick).host
|
||||
if users.exists(nick) and hostmask in [users.get(player).ident + "@" + users.get(player).host for player in pl if users.exists(player)]:
|
||||
if user.userhost in [users._get(player).userhost for player in pl]: # FIXME
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@cmd("spectate", "fspectate", flag="A", pm=True, phases=("day", "night"))
|
||||
def fspectate(cli, nick, chan, rest):
|
||||
@command("spectate", "fspectate", flag="A", pm=True, phases=("day", "night"))
|
||||
def fspectate(var, wrapper, message):
|
||||
"""Spectate wolfchat or deadchat."""
|
||||
if not can_run_restricted_cmd(nick):
|
||||
if not can_run_restricted_cmd(wrapper.source):
|
||||
pm(cli, nick, messages["fspectate_restricted"])
|
||||
return
|
||||
|
||||
params = rest.split(" ")
|
||||
params = message.split(" ")
|
||||
on = "on"
|
||||
if not len(params):
|
||||
pm(cli, nick, messages["fspectate_help"])
|
||||
wrapper.pm(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"])
|
||||
wrapper.pm(messages["fspectate_help"])
|
||||
return
|
||||
|
||||
if on == "off":
|
||||
@ -7450,54 +7432,50 @@ def fspectate(cli, nick, chan, rest):
|
||||
var.SPECTATING_WOLFCHAT.discard(nick)
|
||||
else:
|
||||
var.SPECTATING_DEADCHAT.discard(nick)
|
||||
pm(cli, nick, messages["fspectate_off"].format(what))
|
||||
wrapper.pm(messages["fspectate_off"].format(what))
|
||||
else:
|
||||
players = []
|
||||
if what == "wolfchat":
|
||||
var.SPECTATING_WOLFCHAT.add(nick)
|
||||
players = (p for p in list_players() if in_wolflist(p, p))
|
||||
elif var.ENABLE_DEADCHAT:
|
||||
if nick in var.DEADCHAT_PLAYERS:
|
||||
pm(cli, nick, messages["fspectate_in_deadchat"])
|
||||
if wrapper.source.nick in var.DEADCHAT_PLAYERS: # FIXME
|
||||
wrapper.pm(messages["fspectate_in_deadchat"])
|
||||
return
|
||||
var.SPECTATING_DEADCHAT.add(nick)
|
||||
players = var.DEADCHAT_PLAYERS
|
||||
else:
|
||||
pm(cli, nick, messages["fspectate_deadchat_disabled"])
|
||||
wrapper.pm(messages["fspectate_deadchat_disabled"])
|
||||
return
|
||||
pm(cli, nick, messages["fspectate_on"].format(what))
|
||||
pm(cli, nick, "People in {0}: {1}".format(what, ", ".join(players)))
|
||||
wrapper.pm(messages["fspectate_on"].format(what))
|
||||
wrapper.pm("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:
|
||||
|
||||
@cmd("eval", owner_only=True, pm=True)
|
||||
def pyeval(cli, nick, chan, rest):
|
||||
@command("eval", owner_only=True, pm=True)
|
||||
def pyeval(var, wrapper, message):
|
||||
"""Evaluate a Python expression."""
|
||||
try:
|
||||
a = str(eval(rest))
|
||||
if len(a) < 500:
|
||||
cli.msg(chan, a)
|
||||
else:
|
||||
cli.msg(chan, a[:500])
|
||||
wrapper.send(str(eval(message))[:500])
|
||||
except Exception as e:
|
||||
cli.msg(chan, "{e.__class__.__name__}: {e}".format(e=e))
|
||||
wrapper.send("{e.__class__.__name__}: {e}".format(e=e))
|
||||
|
||||
@cmd("exec", owner_only=True, pm=True)
|
||||
def py(cli, nick, chan, rest):
|
||||
@command("exec", owner_only=True, pm=True)
|
||||
def py(var, wrapper, message):
|
||||
"""Execute arbitrary Python code."""
|
||||
try:
|
||||
exec(rest)
|
||||
exec(message)
|
||||
except Exception as e:
|
||||
cli.msg(chan, "{e.__class__.__name__}: {e}".format(e=e))
|
||||
wrapper.send("{e.__class__.__name__}: {e}".format(e=e))
|
||||
|
||||
@cmd("revealroles", flag="a", pm=True, phases=("day", "night"))
|
||||
def revealroles(cli, nick, chan, rest):
|
||||
@command("revealroles", flag="a", pm=True, phases=("day", "night"))
|
||||
def revealroles(var, wrapper, message):
|
||||
"""Reveal role information."""
|
||||
|
||||
if not can_run_restricted_cmd(nick):
|
||||
reply(cli, nick, chan, messages["temp_invalid_perms"], private=True)
|
||||
if not can_run_restricted_cmd(wrapper.source):
|
||||
wrapper.pm(messages["temp_invalid_perms"])
|
||||
return
|
||||
|
||||
output = []
|
||||
@ -7523,7 +7501,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
if var.TURNCOATS[nickname][0] != "none" else "not currently on any side")
|
||||
|
||||
evt = Event("revealroles_role", {"special_case": special_case})
|
||||
evt.dispatch(cli, var, nickname, role)
|
||||
evt.dispatch(var, wrapper, nickname, role)
|
||||
special_case = evt.data["special_case"]
|
||||
|
||||
if not evt.prevent_default and nickname not in var.ORIGINAL_ROLES[role] and role not in var.TEMPLATE_RESTRICTIONS:
|
||||
@ -7568,12 +7546,12 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
output.append("\u0002charmed players\u0002: {0}".format(", ".join(var.CHARMED | var.TOBECHARMED)))
|
||||
|
||||
evt = Event("revealroles", {"output": output})
|
||||
evt.dispatch(cli, var)
|
||||
evt.dispatch(var, wrapper)
|
||||
|
||||
if botconfig.DEBUG_MODE:
|
||||
cli.msg(chan, break_long_message(output, " | "))
|
||||
wrapper.send(*output, sep=" | ")
|
||||
else:
|
||||
reply(cli, nick, chan, break_long_message(output, " | "), private=True)
|
||||
wrapper.pm(*output, sep=" | ")
|
||||
|
||||
|
||||
@cmd("fgame", flag="d", raw_nick=True, phases=("join",))
|
||||
@ -7661,7 +7639,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
if fn.chan:
|
||||
fn.caller(cli, user, chan, " ".join(rst))
|
||||
else:
|
||||
fn.caller(cli, user, user, " ".join(rst))
|
||||
fn.caller(cli, user, users.Bot.nick, " ".join(rst))
|
||||
cli.msg(chan, messages["operation_successful"])
|
||||
else:
|
||||
cli.msg(chan, messages["command_not_found"])
|
||||
@ -7701,7 +7679,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
if fn.chan:
|
||||
fn.caller(cli, user, chan, " ".join(rst))
|
||||
else:
|
||||
fn.caller(cli, user, user, " ".join(rst))
|
||||
fn.caller(cli, user, users.Bot.nick, " ".join(rst))
|
||||
cli.msg(chan, messages["operation_successful"])
|
||||
else:
|
||||
cli.msg(chan, messages["command_not_found"])
|
||||
|
Loading…
Reference in New Issue
Block a user