autopep8
This commit is contained in:
parent
6f16848302
commit
4189d5c874
@ -1,4 +1,5 @@
|
|||||||
# The bot commands implemented in here are present no matter which module is loaded
|
# The bot commands implemented in here are present no matter which module
|
||||||
|
# is loaded
|
||||||
|
|
||||||
import botconfig
|
import botconfig
|
||||||
from tools import decorators
|
from tools import decorators
|
||||||
@ -9,14 +10,16 @@ from settings import common as var
|
|||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
import imp
|
import imp
|
||||||
|
|
||||||
|
|
||||||
def on_privmsg(cli, rawnick, chan, msg, notice=False):
|
def on_privmsg(cli, rawnick, chan, msg, notice=False):
|
||||||
currmod = ld.MODULES[ld.CURRENT_MODULE]
|
currmod = ld.MODULES[ld.CURRENT_MODULE]
|
||||||
|
|
||||||
if botconfig.IGNORE_HIDDEN_COMMANDS and (chan.startswith("@#") or chan.startswith("+#")):
|
if botconfig.IGNORE_HIDDEN_COMMANDS and (
|
||||||
|
chan.startswith("@#") or chan.startswith("+#")):
|
||||||
return
|
return
|
||||||
|
|
||||||
if (notice and ((chan != botconfig.NICK and not botconfig.ALLOW_NOTICE_COMMANDS) or
|
if (notice and ((chan != botconfig.NICK and not botconfig.ALLOW_NOTICE_COMMANDS) or (
|
||||||
(chan == botconfig.NICK and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
chan == botconfig.NICK and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
||||||
return # not allowed in settings
|
return # not allowed in settings
|
||||||
|
|
||||||
if chan != botconfig.NICK: # not a PM
|
if chan != botconfig.NICK: # not a PM
|
||||||
@ -29,7 +32,9 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
|
|||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
cli.msg(chan, "An error has occurred and has been logged.")
|
cli.msg(
|
||||||
|
chan,
|
||||||
|
"An error has occurred and has been logged.")
|
||||||
# Now that is always called first.
|
# Now that is always called first.
|
||||||
for x in set(list(COMMANDS.keys()) + (list(currmod.COMMANDS.keys()) if currmod else list())):
|
for x in set(list(COMMANDS.keys()) + (list(currmod.COMMANDS.keys()) if currmod else list())):
|
||||||
if x and msg.lower().startswith(botconfig.CMD_CHAR + x):
|
if x and msg.lower().startswith(botconfig.CMD_CHAR + x):
|
||||||
@ -43,7 +48,9 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
|
|||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
cli.msg(chan, "An error has occurred and has been logged.")
|
cli.msg(
|
||||||
|
chan,
|
||||||
|
"An error has occurred and has been logged.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for x in set(list(PM_COMMANDS.keys()) + (list(currmod.PM_COMMANDS.keys()) if currmod else list())):
|
for x in set(list(PM_COMMANDS.keys()) + (list(currmod.PM_COMMANDS.keys()) if currmod else list())):
|
||||||
@ -62,15 +69,21 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
|
|||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
cli.msg(chan, "An error has occurred and has been logged.")
|
cli.msg(
|
||||||
|
chan,
|
||||||
|
"An error has occurred and has been logged.")
|
||||||
|
|
||||||
|
|
||||||
def __unhandled__(cli, prefix, cmd, *args):
|
def __unhandled__(cli, prefix, cmd, *args):
|
||||||
currmod = ld.MODULES[ld.CURRENT_MODULE]
|
currmod = ld.MODULES[ld.CURRENT_MODULE]
|
||||||
|
|
||||||
if cmd in set(list(HOOKS.keys())+(list(currmod.HOOKS.keys()) if currmod else list())):
|
if cmd in set(
|
||||||
|
list(HOOKS.keys()) +
|
||||||
|
(list(currmod.HOOKS.keys()) if currmod else list())):
|
||||||
largs = list(args)
|
largs = list(args)
|
||||||
for i, arg in enumerate(largs):
|
for i, arg in enumerate(largs):
|
||||||
if isinstance(arg, bytes): largs[i] = arg.decode('ascii')
|
if isinstance(arg, bytes):
|
||||||
|
largs[i] = arg.decode('ascii')
|
||||||
for fn in HOOKS.get(cmd, []) + (currmod.HOOKS.get(cmd, []) if currmod else []):
|
for fn in HOOKS.get(cmd, []) + (currmod.HOOKS.get(cmd, []) if currmod else []):
|
||||||
try:
|
try:
|
||||||
fn(cli, prefix, *largs)
|
fn(cli, prefix, *largs)
|
||||||
@ -79,11 +92,15 @@ def __unhandled__(cli, prefix, cmd, *args):
|
|||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
cli.msg(botconfig.CHANNEL, "An error has occurred and has been logged.")
|
cli.msg(
|
||||||
|
botconfig.CHANNEL,
|
||||||
|
"An error has occurred and has been logged.")
|
||||||
else:
|
else:
|
||||||
logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8')
|
logging.debug(
|
||||||
for arg in args
|
'Unhandled command {0}({1})'.format(
|
||||||
if isinstance(arg, bytes)]))
|
cmd, [
|
||||||
|
arg.decode('utf_8') for arg in args if isinstance(
|
||||||
|
arg, bytes)]))
|
||||||
|
|
||||||
|
|
||||||
COMMANDS = {}
|
COMMANDS = {}
|
||||||
@ -94,6 +111,7 @@ cmd = decorators.generate(COMMANDS)
|
|||||||
pmcmd = decorators.generate(PM_COMMANDS)
|
pmcmd = decorators.generate(PM_COMMANDS)
|
||||||
hook = decorators.generate(HOOKS, raw_nick=True, permissions=False)
|
hook = decorators.generate(HOOKS, raw_nick=True, permissions=False)
|
||||||
|
|
||||||
|
|
||||||
def connect_callback(cli):
|
def connect_callback(cli):
|
||||||
|
|
||||||
def prepare_stuff(*args):
|
def prepare_stuff(*args):
|
||||||
@ -134,10 +152,14 @@ def connect_callback(cli):
|
|||||||
@hook("authenticate")
|
@hook("authenticate")
|
||||||
def auth_plus(cli, something, plus):
|
def auth_plus(cli, something, plus):
|
||||||
if plus == "+":
|
if plus == "+":
|
||||||
nick_b = bytes(botconfig.USERNAME if botconfig.USERNAME else botconfig.NICK, "utf-8")
|
nick_b = bytes(
|
||||||
|
botconfig.USERNAME if botconfig.USERNAME else botconfig.NICK,
|
||||||
|
"utf-8")
|
||||||
pass_b = bytes(botconfig.PASS, "utf-8")
|
pass_b = bytes(botconfig.PASS, "utf-8")
|
||||||
secrt_msg = b'\0'.join((nick_b, nick_b, pass_b))
|
secrt_msg = b'\0'.join((nick_b, nick_b, pass_b))
|
||||||
cli.send("AUTHENTICATE " + b64encode(secrt_msg).decode("utf-8"))
|
cli.send(
|
||||||
|
"AUTHENTICATE " +
|
||||||
|
b64encode(secrt_msg).decode("utf-8"))
|
||||||
|
|
||||||
@hook("cap")
|
@hook("cap")
|
||||||
def on_cap(cli, svr, mynick, ack, cap):
|
def on_cap(cli, svr, mynick, ack, cap):
|
||||||
@ -158,13 +180,11 @@ def connect_callback(cli):
|
|||||||
"in botconfig.USERNAME if it's different from the bot nick?")
|
"in botconfig.USERNAME if it's different from the bot nick?")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@hook("ping")
|
@hook("ping")
|
||||||
def on_ping(cli, prefix, server):
|
def on_ping(cli, prefix, server):
|
||||||
cli.send('PONG', server)
|
cli.send('PONG', server)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if botconfig.DEBUG_MODE:
|
if botconfig.DEBUG_MODE:
|
||||||
@cmd("module", admin_only=True)
|
@cmd("module", admin_only=True)
|
||||||
def ch_module(cli, nick, chan, rest):
|
def ch_module(cli, nick, chan, rest):
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,13 +24,18 @@ import ssl
|
|||||||
|
|
||||||
from oyoyo.parse import parse_raw_irc_command
|
from oyoyo.parse import parse_raw_irc_command
|
||||||
|
|
||||||
# Adapted from http://code.activestate.com/recipes/511490-implementation-of-the-token-bucket-algorithm/
|
# Adapted from
|
||||||
|
# http://code.activestate.com/recipes/511490-implementation-of-the-token-bucket-algorithm/
|
||||||
|
|
||||||
|
|
||||||
class TokenBucket(object):
|
class TokenBucket(object):
|
||||||
|
|
||||||
"""An implementation of the token bucket algorithm.
|
"""An implementation of the token bucket algorithm.
|
||||||
|
|
||||||
>>> bucket = TokenBucket(80, 0.5)
|
>>> bucket = TokenBucket(80, 0.5)
|
||||||
>>> bucket.consume(1)
|
>>> bucket.consume(1)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, tokens, fill_rate):
|
def __init__(self, tokens, fill_rate):
|
||||||
"""tokens is the total tokens in the bucket. fill_rate is the
|
"""tokens is the total tokens in the bucket. fill_rate is the
|
||||||
rate in tokens/second that the bucket will be refilled."""
|
rate in tokens/second that the bucket will be refilled."""
|
||||||
@ -57,7 +62,6 @@ class TokenBucket(object):
|
|||||||
return self._tokens
|
return self._tokens
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_commands(d):
|
def add_commands(d):
|
||||||
def dec(cls):
|
def dec(cls):
|
||||||
for c in d:
|
for c in d:
|
||||||
@ -68,12 +72,15 @@ def add_commands(d):
|
|||||||
setattr(cls, c, func(c))
|
setattr(cls, c, func(c))
|
||||||
return cls
|
return cls
|
||||||
return dec
|
return dec
|
||||||
|
|
||||||
|
|
||||||
@add_commands(("join",
|
@add_commands(("join",
|
||||||
"mode",
|
"mode",
|
||||||
"nick",
|
"nick",
|
||||||
"who",
|
"who",
|
||||||
"cap"))
|
"cap"))
|
||||||
class IRCClient(object):
|
class IRCClient(object):
|
||||||
|
|
||||||
""" IRC Client class. This handles one connection to a server.
|
""" IRC Client class. This handles one connection to a server.
|
||||||
This can be used either with or without IRCApp ( see connect() docs )
|
This can be used either with or without IRCApp ( see connect() docs )
|
||||||
"""
|
"""
|
||||||
@ -148,9 +155,14 @@ class IRCClient(object):
|
|||||||
elif arg is None:
|
elif arg is None:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
raise Exception(('Refusing to send arg at index {1} of the args from '+
|
raise Exception(
|
||||||
'provided: {0}').format(repr([(type(arg), arg)
|
('Refusing to send arg at index {1} of the args from ' +
|
||||||
for arg in args]), i))
|
'provided: {0}').format(
|
||||||
|
repr(
|
||||||
|
[
|
||||||
|
(type(arg),
|
||||||
|
arg) for arg in args]),
|
||||||
|
i))
|
||||||
|
|
||||||
msg = bytes(" ", "utf_8").join(bargs)
|
msg = bytes(" ", "utf_8").join(bargs)
|
||||||
logging.info('---> send {0}'.format(str(msg)[1:]))
|
logging.info('---> send {0}'.format(str(msg)[1:]))
|
||||||
@ -185,7 +197,9 @@ class IRCClient(object):
|
|||||||
self.socket.setblocking(0)
|
self.socket.setblocking(0)
|
||||||
|
|
||||||
if not self.sasl_auth:
|
if not self.sasl_auth:
|
||||||
self.send("PASS {0}:{1}".format(self.authname if self.authname else self.nickname,
|
self.send(
|
||||||
|
"PASS {0}:{1}".format(
|
||||||
|
self.authname if self.authname else self.nickname,
|
||||||
self.password if self.password else "NOPASS"))
|
self.password if self.password else "NOPASS"))
|
||||||
else:
|
else:
|
||||||
self.cap("LS")
|
self.cap("LS")
|
||||||
@ -222,13 +236,22 @@ class IRCClient(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
enc = "utf8"
|
enc = "utf8"
|
||||||
fargs = [arg.decode(enc) for arg in args if isinstance(arg,bytes)]
|
fargs = [
|
||||||
|
arg.decode(enc) for arg in args if isinstance(
|
||||||
|
arg,
|
||||||
|
bytes)]
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
enc = "latin1"
|
enc = "latin1"
|
||||||
fargs = [arg.decode(enc) for arg in args if isinstance(arg,bytes)]
|
fargs = [
|
||||||
|
arg.decode(enc) for arg in args if isinstance(
|
||||||
|
arg,
|
||||||
|
bytes)]
|
||||||
|
|
||||||
logging.debug("processCommand ({2}){0}({1})".format(command,
|
logging.debug(
|
||||||
fargs, prefix))
|
"processCommand ({2}){0}({1})".format(
|
||||||
|
command,
|
||||||
|
fargs,
|
||||||
|
prefix))
|
||||||
try:
|
try:
|
||||||
largs = list(args)
|
largs = list(args)
|
||||||
if prefix is not None:
|
if prefix is not None:
|
||||||
@ -236,9 +259,18 @@ class IRCClient(object):
|
|||||||
# for i,arg in enumerate(largs):
|
# for i,arg in enumerate(largs):
|
||||||
# if arg is not None: largs[i] = arg.decode(enc)
|
# if arg is not None: largs[i] = arg.decode(enc)
|
||||||
if command in self.command_handler:
|
if command in self.command_handler:
|
||||||
self.command_handler[command](self, prefix,*fargs)
|
self.command_handler[command](
|
||||||
|
self,
|
||||||
|
prefix,
|
||||||
|
*
|
||||||
|
fargs)
|
||||||
elif "" in self.command_handler:
|
elif "" in self.command_handler:
|
||||||
self.command_handler[""](self, prefix, command, *fargs)
|
self.command_handler[""](
|
||||||
|
self,
|
||||||
|
prefix,
|
||||||
|
command,
|
||||||
|
*
|
||||||
|
fargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
raise e # ?
|
raise e # ?
|
||||||
@ -248,9 +280,11 @@ class IRCClient(object):
|
|||||||
logging.info('closing socket')
|
logging.info('closing socket')
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
yield False
|
yield False
|
||||||
|
|
||||||
def msg(self, user, msg):
|
def msg(self, user, msg):
|
||||||
for line in msg.split('\n'):
|
for line in msg.split('\n'):
|
||||||
maxchars = 494 - len(self.nickname+self.ident+self.hostmask+user)
|
maxchars = 494 - len(
|
||||||
|
self.nickname + self.ident + self.hostmask + user)
|
||||||
while line:
|
while line:
|
||||||
extra = ""
|
extra = ""
|
||||||
if len(line) > maxchars:
|
if len(line) > maxchars:
|
||||||
@ -259,9 +293,11 @@ class IRCClient(object):
|
|||||||
self.send("PRIVMSG", user, ":{0}".format(line))
|
self.send("PRIVMSG", user, ":{0}".format(line))
|
||||||
line = extra
|
line = extra
|
||||||
privmsg = msg # Same thing
|
privmsg = msg # Same thing
|
||||||
|
|
||||||
def notice(self, user, msg):
|
def notice(self, user, msg):
|
||||||
for line in msg.split('\n'):
|
for line in msg.split('\n'):
|
||||||
maxchars = 495 - len(self.nickname+self.ident+self.hostmask+user)
|
maxchars = 495 - len(
|
||||||
|
self.nickname + self.ident + self.hostmask + user)
|
||||||
while line:
|
while line:
|
||||||
extra = ""
|
extra = ""
|
||||||
if len(line) > maxchars:
|
if len(line) > maxchars:
|
||||||
@ -269,27 +305,35 @@ class IRCClient(object):
|
|||||||
line = line[:maxchars]
|
line = line[:maxchars]
|
||||||
self.send("NOTICE", user, ":{0}".format(line))
|
self.send("NOTICE", user, ":{0}".format(line))
|
||||||
line = extra
|
line = extra
|
||||||
|
|
||||||
def quit(self, msg=""):
|
def quit(self, msg=""):
|
||||||
self.send("QUIT :{0}".format(msg))
|
self.send("QUIT :{0}".format(msg))
|
||||||
|
|
||||||
def part(self, chan, msg=""):
|
def part(self, chan, msg=""):
|
||||||
self.send("PART {0} :{1}".format(chan, msg))
|
self.send("PART {0} :{1}".format(chan, msg))
|
||||||
|
|
||||||
def kick(self, chan, nick, msg=""):
|
def kick(self, chan, nick, msg=""):
|
||||||
self.send("KICK", chan, nick, ":" + msg)
|
self.send("KICK", chan, nick, ":" + msg)
|
||||||
|
|
||||||
def ns_identify(self, passwd):
|
def ns_identify(self, passwd):
|
||||||
self.msg("NickServ", "IDENTIFY {0} {1}".format(self.nickname, passwd))
|
self.msg("NickServ", "IDENTIFY {0} {1}".format(self.nickname, passwd))
|
||||||
|
|
||||||
def ns_ghost(self):
|
def ns_ghost(self):
|
||||||
self.msg("NickServ", "GHOST " + self.nickname)
|
self.msg("NickServ", "GHOST " + self.nickname)
|
||||||
|
|
||||||
def ns_release(self):
|
def ns_release(self):
|
||||||
self.msg("NickServ", "RELEASE " + self.nickname)
|
self.msg("NickServ", "RELEASE " + self.nickname)
|
||||||
|
|
||||||
def ns_regain(self):
|
def ns_regain(self):
|
||||||
self.msg("NickServ", "REGAIN " + self.nickname)
|
self.msg("NickServ", "REGAIN " + self.nickname)
|
||||||
|
|
||||||
def user(self, uname, rname):
|
def user(self, uname, rname):
|
||||||
self.send("USER", uname, self.host, self.host,
|
self.send("USER", uname, self.host, self.host,
|
||||||
rname or uname)
|
rname or uname)
|
||||||
|
|
||||||
def mainLoop(self):
|
def mainLoop(self):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
while True:
|
while True:
|
||||||
if not next(conn):
|
if not next(conn):
|
||||||
print("Calling sys.exit()...")
|
print("Calling sys.exit()...")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
@ -208,4 +208,3 @@ protocol_events = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
all_events = generated_events + protocol_events + list(numeric_events.values())
|
all_events = generated_events + protocol_events + list(numeric_events.values())
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ from oyoyo.ircevents import generated_events, protocol_events,\
|
|||||||
all_events, numeric_events
|
all_events, numeric_events
|
||||||
|
|
||||||
# avoiding regex
|
# avoiding regex
|
||||||
|
|
||||||
|
|
||||||
def parse_raw_irc_command(element):
|
def parse_raw_irc_command(element):
|
||||||
"""
|
"""
|
||||||
This function parses a raw irc command and returns a tuple
|
This function parses a raw irc command and returns a tuple
|
||||||
@ -56,7 +58,8 @@ def parse_raw_irc_command(element):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
logging.debug('unknown numeric event {0}'.format(command))
|
logging.debug('unknown numeric event {0}'.format(command))
|
||||||
command = command.lower()
|
command = command.lower()
|
||||||
if isinstance(command, bytes): command = command.decode("utf_8")
|
if isinstance(command, bytes):
|
||||||
|
command = command.decode("utf_8")
|
||||||
|
|
||||||
if args[0].startswith(bytes(':', 'utf_8')):
|
if args[0].startswith(bytes(':', 'utf_8')):
|
||||||
args = [bytes(" ", "utf_8").join(args)[1:]]
|
args = [bytes(" ", "utf_8").join(args)[1:]]
|
||||||
@ -89,4 +92,3 @@ def parse_nick(name):
|
|||||||
return (nick, mode, rest, None)
|
return (nick, mode, rest, None)
|
||||||
|
|
||||||
return (nick, mode, user, host)
|
return (nick, mode, user, host)
|
||||||
|
|
||||||
|
@ -31,25 +31,26 @@ GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE = 0
|
|||||||
GUARDIAN_ANGEL_DIES_CHANCE = 1 / 2
|
GUARDIAN_ANGEL_DIES_CHANCE = 1 / 2
|
||||||
DETECTIVE_REVEALED_CHANCE = 2 / 5
|
DETECTIVE_REVEALED_CHANCE = 2 / 5
|
||||||
|
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
|
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
ROLES_GUIDE = {4: (1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
6 : ( 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
6: (1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
|
||||||
8 : ( 1 , 2 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ), ##
|
8: (1, 2, 1, 1, 1, 0, 0, 0, 0, 0),
|
||||||
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ), ##
|
10: (1, 2, 1, 1, 1, 1, 1, 0, 0, 0),
|
||||||
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 ), ##
|
11: (1, 2, 1, 1, 1, 1, 1, 0, 1, 0),
|
||||||
15 : ( 1 , 3 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
|
15: (1, 3, 1, 1, 1, 1, 1, 0, 1, 1),
|
||||||
22 : ( 1 , 4 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
|
22: (1, 4, 1, 1, 1, 1, 1, 0, 1, 1),
|
||||||
29 : ( 1 , 5 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
|
29: (1, 5, 1, 1, 1, 1, 1, 0, 1, 1),
|
||||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
|
None: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)}
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
# Notes: ##
|
# Notes: ##
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
|
|
||||||
GAME_MODES = {}
|
GAME_MODES = {}
|
||||||
AWAY = [] # cloaks of people who are away.
|
AWAY = [] # cloaks of people who are away.
|
||||||
SIMPLE_NOTIFY = [] # cloaks of people who !simple, who want everything /notice'd
|
# cloaks of people who !simple, who want everything /notice'd
|
||||||
|
SIMPLE_NOTIFY = []
|
||||||
|
|
||||||
ROLE_INDICES = {0: "seer",
|
ROLE_INDICES = {0: "seer",
|
||||||
1: "wolf",
|
1: "wolf",
|
||||||
@ -68,14 +69,17 @@ INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
|
|||||||
NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.",
|
NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.",
|
||||||
"A pool of blood and wolf paw prints are found.",
|
"A pool of blood and wolf paw prints are found.",
|
||||||
"Traces of wolf fur are found.")
|
"Traces of wolf fur are found.")
|
||||||
LYNCH_MESSAGES = ("The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
LYNCH_MESSAGES = (
|
||||||
|
"The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
||||||
"Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
"Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
||||||
"The mob drags a protesting \u0002{0}\u0002 to the hanging tree. S/He succumbs to the will of the horde, and is hanged. It is discovered (s)he was a \u0002{1}\u0002.",
|
"The mob drags a protesting \u0002{0}\u0002 to the hanging tree. S/He succumbs to the will of the horde, and is hanged. It is discovered (s)he was a \u0002{1}\u0002.",
|
||||||
"Resigned to his/her fate, \u0002{0}\u0002 is led to the gallows. After death, it is discovered (s)he was a \u0002{1}\u0002.")
|
"Resigned to his/her fate, \u0002{0}\u0002 is led to the gallows. After death, it is discovered (s)he was a \u0002{1}\u0002.")
|
||||||
|
|
||||||
import botconfig
|
import botconfig
|
||||||
|
|
||||||
RULES = (botconfig.CHANNEL + " channel rules: 1) Be nice to others. 2) Do not share information "+
|
RULES = (
|
||||||
|
botconfig.CHANNEL +
|
||||||
|
" channel rules: 1) Be nice to others. 2) Do not share information " +
|
||||||
"after death. 3) No bots allowed. 4) Do not play with clones.\n" +
|
"after death. 3) No bots allowed. 4) Do not play with clones.\n" +
|
||||||
"5) Do not quit unless you need to leave. 6) No swearing and keep it " +
|
"5) Do not quit unless you need to leave. 6) No swearing and keep it " +
|
||||||
"family-friendly. 7) Do not paste PM's from the bot during the game. " +
|
"family-friendly. 7) Do not paste PM's from the bot during the game. " +
|
||||||
@ -83,17 +87,23 @@ RULES = (botconfig.CHANNEL + " channel rules: 1) Be nice to others. 2) Do not sh
|
|||||||
|
|
||||||
# Other settings:
|
# Other settings:
|
||||||
START_WITH_DAY = False
|
START_WITH_DAY = False
|
||||||
WOLF_STEALS_GUN = False # at night, the wolf can steal steal the victim's bullets
|
# at night, the wolf can steal steal the victim's bullets
|
||||||
|
WOLF_STEALS_GUN = False
|
||||||
|
|
||||||
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
||||||
PING_IN = [] # cloaks of users who have opted in for ping
|
PING_IN = [] # cloaks of users who have opted in for ping
|
||||||
|
|
||||||
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
|
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
|
||||||
|
|
||||||
|
|
||||||
def plural(role):
|
def plural(role):
|
||||||
if role == "wolf": return "wolves"
|
if role == "wolf":
|
||||||
elif role == "person": return "people"
|
return "wolves"
|
||||||
else: return role + "s"
|
elif role == "person":
|
||||||
|
return "people"
|
||||||
|
else:
|
||||||
|
return role + "s"
|
||||||
|
|
||||||
|
|
||||||
def list_players():
|
def list_players():
|
||||||
pl = []
|
pl = []
|
||||||
@ -101,6 +111,7 @@ def list_players():
|
|||||||
pl.extend(x)
|
pl.extend(x)
|
||||||
return pl
|
return pl
|
||||||
|
|
||||||
|
|
||||||
def list_players_and_roles():
|
def list_players_and_roles():
|
||||||
plr = {}
|
plr = {}
|
||||||
for x in ROLES.keys():
|
for x in ROLES.keys():
|
||||||
@ -116,8 +127,10 @@ def del_player(pname):
|
|||||||
ROLES[prole].remove(pname)
|
ROLES[prole].remove(pname)
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidModeException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidModeException(Exception): pass
|
|
||||||
def game_mode(name):
|
def game_mode(name):
|
||||||
def decor(c):
|
def decor(c):
|
||||||
GAME_MODES[name] = c
|
GAME_MODES[name] = c
|
||||||
@ -137,11 +150,10 @@ CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"],
|
|||||||
"detectives": INDEX_OF_ROLE["detective"]}
|
"detectives": INDEX_OF_ROLE["detective"]}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: implement game modes
|
# TODO: implement game modes
|
||||||
@game_mode("roles")
|
@game_mode("roles")
|
||||||
class ChangedRolesMode(object):
|
class ChangedRolesMode(object):
|
||||||
|
|
||||||
"""Example: !fgame roles=wolves:1,seers:0,angels:1"""
|
"""Example: !fgame roles=wolves:1,seers:0,angels:1"""
|
||||||
|
|
||||||
def __init__(self, arg):
|
def __init__(self, arg):
|
||||||
@ -164,7 +176,8 @@ class ChangedRolesMode(object):
|
|||||||
raise InvalidModeException(("The role \u0002{0}\u0002 " +
|
raise InvalidModeException(("The role \u0002{0}\u0002 " +
|
||||||
"is not valid.").format(role))
|
"is not valid.").format(role))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise InvalidModeException("A bad value was used in mode roles.")
|
raise InvalidModeException(
|
||||||
|
"A bad value was used in mode roles.")
|
||||||
for k in ROLES_GUIDE.keys():
|
for k in ROLES_GUIDE.keys():
|
||||||
self.ROLES_GUIDE[k] = tuple(lx)
|
self.ROLES_GUIDE[k] = tuple(lx)
|
||||||
|
|
||||||
@ -180,9 +193,11 @@ conn = sqlite3.connect("data.sqlite3", check_same_thread = False)
|
|||||||
|
|
||||||
with conn:
|
with conn:
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS away (nick TEXT)') # whoops, i mean cloak, not nick
|
# whoops, i mean cloak, not nick
|
||||||
|
c.execute('CREATE TABLE IF NOT EXISTS away (nick TEXT)')
|
||||||
|
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS simple_role_notify (cloak TEXT)') # people who understand each role
|
# people who understand each role
|
||||||
|
c.execute('CREATE TABLE IF NOT EXISTS simple_role_notify (cloak TEXT)')
|
||||||
|
|
||||||
c.execute('SELECT * FROM away')
|
c.execute('SELECT * FROM away')
|
||||||
for row in c:
|
for row in c:
|
||||||
@ -194,13 +209,14 @@ with conn:
|
|||||||
|
|
||||||
# populate the roles table
|
# populate the roles table
|
||||||
c.execute('DROP TABLE IF EXISTS roles')
|
c.execute('DROP TABLE IF EXISTS roles')
|
||||||
c.execute('CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)')
|
c.execute(
|
||||||
|
'CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)')
|
||||||
|
|
||||||
for x in ["villager"] + list(ROLE_INDICES.values()):
|
for x in ["villager"] + list(ROLE_INDICES.values()):
|
||||||
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
||||||
|
|
||||||
|
c.execute(
|
||||||
c.execute(('CREATE TABLE IF NOT EXISTS rolestats (player TEXT, role TEXT, '+
|
('CREATE TABLE IF NOT EXISTS rolestats (player TEXT, role TEXT, ' +
|
||||||
'teamwins SMALLINT, individualwins SMALLINT, totalgames SMALLINT, ' +
|
'teamwins SMALLINT, individualwins SMALLINT, totalgames SMALLINT, ' +
|
||||||
'UNIQUE(player, role))'))
|
'UNIQUE(player, role))'))
|
||||||
|
|
||||||
@ -216,21 +232,27 @@ def remove_away(clk):
|
|||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from away where nick=?', (clk,))
|
c.execute('DELETE from away where nick=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_away(clk):
|
def add_away(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into away VALUES (?)', (clk,))
|
c.execute('INSERT into away VALUES (?)', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def remove_simple_rolemsg(clk):
|
def remove_simple_rolemsg(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from simple_role_notify where cloak=?', (clk,))
|
c.execute('DELETE from simple_role_notify where cloak=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_simple_rolemsg(clk):
|
def add_simple_rolemsg(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into simple_role_notify VALUES (?)', (clk,))
|
c.execute('INSERT into simple_role_notify VALUES (?)', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def remove_ping(clk):
|
def remove_ping(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from ping where cloak=?', (clk,))
|
c.execute('DELETE from ping where cloak=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_ping(clk):
|
def add_ping(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into ping VALUES (?)', (clk,))
|
c.execute('INSERT into ping VALUES (?)', (clk,))
|
||||||
@ -241,8 +263,10 @@ def update_role_stats(acc, role, won, iwon):
|
|||||||
with conn:
|
with conn:
|
||||||
wins, iwins, totalgames = 0, 0, 0
|
wins, iwins, totalgames = 0, 0, 0
|
||||||
|
|
||||||
c.execute(("SELECT teamwins, individualwins, totalgames FROM rolestats "+
|
c.execute(
|
||||||
"WHERE player=? AND role=?"), (acc, role))
|
("SELECT teamwins, individualwins, totalgames FROM rolestats " +
|
||||||
|
"WHERE player=? AND role=?"),
|
||||||
|
(acc, role))
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
if row:
|
if row:
|
||||||
wins, iwins, total = row
|
wins, iwins, total = row
|
||||||
@ -257,6 +281,3 @@ def update_role_stats(acc, role, won, iwon):
|
|||||||
|
|
||||||
c.execute("INSERT OR REPLACE INTO rolestats VALUES (?,?,?,?,?)",
|
c.execute("INSERT OR REPLACE INTO rolestats VALUES (?,?,?,?,?)",
|
||||||
(acc, role, wins, iwins, total))
|
(acc, role, wins, iwins, total))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ KILL_IDLE_TIME = 300
|
|||||||
WARN_IDLE_TIME = 180
|
WARN_IDLE_TIME = 180
|
||||||
PART_GRACE_TIME = 30
|
PART_GRACE_TIME = 30
|
||||||
QUIT_GRACE_TIME = 30
|
QUIT_GRACE_TIME = 30
|
||||||
# controls how many people it does in one /msg; only works for messages that are the same
|
# controls how many people it does in one /msg; only works for messages
|
||||||
|
# that are the same
|
||||||
MAX_PRIVMSG_TARGETS = 4
|
MAX_PRIVMSG_TARGETS = 4
|
||||||
LEAVE_STASIS_PENALTY = 1
|
LEAVE_STASIS_PENALTY = 1
|
||||||
IDLE_STASIS_PENALTY = 1
|
IDLE_STASIS_PENALTY = 1
|
||||||
@ -56,26 +57,27 @@ GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE = 1/4
|
|||||||
GUARDIAN_ANGEL_DIES_CHANCE = 1 / 2
|
GUARDIAN_ANGEL_DIES_CHANCE = 1 / 2
|
||||||
DETECTIVE_REVEALED_CHANCE = 2 / 5
|
DETECTIVE_REVEALED_CHANCE = 2 / 5
|
||||||
|
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
|
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
ROLES_GUIDE = {4: (1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
6 : ( 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
6: (1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
|
||||||
8 : ( 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 ), ##
|
8: (1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
|
||||||
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ), ##
|
10: (1, 2, 1, 1, 1, 1, 1, 0, 0, 0),
|
||||||
12 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ), ##
|
12: (1, 2, 1, 1, 1, 1, 1, 1, 0, 1),
|
||||||
15 : ( 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ), ##
|
15: (1, 3, 1, 1, 1, 1, 1, 1, 0, 1),
|
||||||
17 : ( 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
17: (1, 3, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
18 : ( 1 , 3 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
18: (1, 3, 2, 1, 1, 1, 1, 1, 1, 1),
|
||||||
20 : ( 1 , 4 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
20: (1, 4, 2, 1, 1, 1, 1, 1, 1, 1),
|
||||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
|
None: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)}
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
# Notes: ##
|
# Notes: ##
|
||||||
#################################################################################################################
|
##########################################################################
|
||||||
|
|
||||||
GAME_MODES = {}
|
GAME_MODES = {}
|
||||||
AWAY = ['services.', 'services.int'] # cloaks of people who are away.
|
AWAY = ['services.', 'services.int'] # cloaks of people who are away.
|
||||||
SIMPLE_NOTIFY = [] # cloaks of people who !simple, who want everything /notice'd
|
# cloaks of people who !simple, who want everything /notice'd
|
||||||
|
SIMPLE_NOTIFY = []
|
||||||
|
|
||||||
ROLE_INDICES = {0: "seer",
|
ROLE_INDICES = {0: "seer",
|
||||||
1: "wolf",
|
1: "wolf",
|
||||||
@ -93,7 +95,8 @@ INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
|
|||||||
NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.",
|
NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.",
|
||||||
"A pool of blood and wolf paw prints are found.",
|
"A pool of blood and wolf paw prints are found.",
|
||||||
"Traces of wolf fur are found.")
|
"Traces of wolf fur are found.")
|
||||||
LYNCH_MESSAGES = ("The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
LYNCH_MESSAGES = (
|
||||||
|
"The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
||||||
"Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
"Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a \u0002{1}\u0002.",
|
||||||
"Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a \u0002{1}\u0002.",
|
"Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a \u0002{1}\u0002.",
|
||||||
"Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a \u0002{1}\u0002.",
|
"Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a \u0002{1}\u0002.",
|
||||||
@ -105,17 +108,23 @@ RULES = (botconfig.CHANNEL + " channel rules: http://wolf.xnrand.com/rules")
|
|||||||
|
|
||||||
# Other settings:
|
# Other settings:
|
||||||
START_WITH_DAY = False
|
START_WITH_DAY = False
|
||||||
WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets
|
# at night, the wolf can steal steal the victim's bullets
|
||||||
|
WOLF_STEALS_GUN = True
|
||||||
|
|
||||||
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
||||||
PING_IN = [] # cloaks of users who have opted in for ping
|
PING_IN = [] # cloaks of users who have opted in for ping
|
||||||
|
|
||||||
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
|
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
|
||||||
|
|
||||||
|
|
||||||
def plural(role):
|
def plural(role):
|
||||||
if role == "wolf": return "wolves"
|
if role == "wolf":
|
||||||
elif role == "person": return "people"
|
return "wolves"
|
||||||
else: return role + "s"
|
elif role == "person":
|
||||||
|
return "people"
|
||||||
|
else:
|
||||||
|
return role + "s"
|
||||||
|
|
||||||
|
|
||||||
def list_players():
|
def list_players():
|
||||||
pl = []
|
pl = []
|
||||||
@ -123,6 +132,7 @@ def list_players():
|
|||||||
pl.extend(x)
|
pl.extend(x)
|
||||||
return pl
|
return pl
|
||||||
|
|
||||||
|
|
||||||
def list_players_and_roles():
|
def list_players_and_roles():
|
||||||
plr = {}
|
plr = {}
|
||||||
for x in ROLES.keys():
|
for x in ROLES.keys():
|
||||||
@ -132,19 +142,23 @@ def list_players_and_roles():
|
|||||||
|
|
||||||
get_role = lambda plyr: list_players_and_roles()[plyr]
|
get_role = lambda plyr: list_players_and_roles()[plyr]
|
||||||
|
|
||||||
|
|
||||||
def get_reveal_role(nick):
|
def get_reveal_role(nick):
|
||||||
if HIDDEN_TRAITOR and get_role(nick) == "traitor":
|
if HIDDEN_TRAITOR and get_role(nick) == "traitor":
|
||||||
return "villager"
|
return "villager"
|
||||||
else:
|
else:
|
||||||
return get_role(nick)
|
return get_role(nick)
|
||||||
|
|
||||||
|
|
||||||
def del_player(pname):
|
def del_player(pname):
|
||||||
prole = get_role(pname)
|
prole = get_role(pname)
|
||||||
ROLES[prole].remove(pname)
|
ROLES[prole].remove(pname)
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidModeException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidModeException(Exception): pass
|
|
||||||
def game_mode(name):
|
def game_mode(name):
|
||||||
def decor(c):
|
def decor(c):
|
||||||
GAME_MODES[name] = c
|
GAME_MODES[name] = c
|
||||||
@ -164,11 +178,10 @@ CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"],
|
|||||||
"detectives": INDEX_OF_ROLE["detective"]}
|
"detectives": INDEX_OF_ROLE["detective"]}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: implement game modes
|
# TODO: implement game modes
|
||||||
@game_mode("roles")
|
@game_mode("roles")
|
||||||
class ChangedRolesMode(object):
|
class ChangedRolesMode(object):
|
||||||
|
|
||||||
"""Example: !fgame roles=wolves:1,seers:0,angels:1"""
|
"""Example: !fgame roles=wolves:1,seers:0,angels:1"""
|
||||||
|
|
||||||
def __init__(self, arg):
|
def __init__(self, arg):
|
||||||
@ -190,7 +203,8 @@ class ChangedRolesMode(object):
|
|||||||
raise InvalidModeException(("The role \u0002{0}\u0002 " +
|
raise InvalidModeException(("The role \u0002{0}\u0002 " +
|
||||||
"is not valid.").format(role))
|
"is not valid.").format(role))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise InvalidModeException("A bad value was used in mode roles.")
|
raise InvalidModeException(
|
||||||
|
"A bad value was used in mode roles.")
|
||||||
for k in ROLES_GUIDE.keys():
|
for k in ROLES_GUIDE.keys():
|
||||||
self.ROLES_GUIDE[k] = tuple(lx)
|
self.ROLES_GUIDE[k] = tuple(lx)
|
||||||
|
|
||||||
@ -205,9 +219,11 @@ conn = sqlite3.connect("data.sqlite3", check_same_thread = False)
|
|||||||
|
|
||||||
with conn:
|
with conn:
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS away (nick TEXT)') # whoops, i mean cloak, not nick
|
# whoops, i mean cloak, not nick
|
||||||
|
c.execute('CREATE TABLE IF NOT EXISTS away (nick TEXT)')
|
||||||
|
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS simple_role_notify (cloak TEXT)') # people who understand each role
|
# people who understand each role
|
||||||
|
c.execute('CREATE TABLE IF NOT EXISTS simple_role_notify (cloak TEXT)')
|
||||||
|
|
||||||
c.execute('SELECT * FROM away')
|
c.execute('SELECT * FROM away')
|
||||||
for row in c:
|
for row in c:
|
||||||
@ -219,21 +235,21 @@ with conn:
|
|||||||
|
|
||||||
# populate the roles table
|
# populate the roles table
|
||||||
c.execute('DROP TABLE IF EXISTS roles')
|
c.execute('DROP TABLE IF EXISTS roles')
|
||||||
c.execute('CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)')
|
c.execute(
|
||||||
|
'CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)')
|
||||||
|
|
||||||
for x in ["villager"] + list(ROLE_INDICES.values()):
|
for x in ["villager"] + list(ROLE_INDICES.values()):
|
||||||
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
||||||
|
|
||||||
|
c.execute(
|
||||||
c.execute(('CREATE TABLE IF NOT EXISTS rolestats (player TEXT, role TEXT, '+
|
('CREATE TABLE IF NOT EXISTS rolestats (player TEXT, role TEXT, ' +
|
||||||
'teamwins SMALLINT, individualwins SMALLINT, totalgames SMALLINT, ' +
|
'teamwins SMALLINT, individualwins SMALLINT, totalgames SMALLINT, ' +
|
||||||
'UNIQUE(player, role))'))
|
'UNIQUE(player, role))'))
|
||||||
|
|
||||||
|
c.execute(
|
||||||
c.execute(('CREATE TABLE IF NOT EXISTS gamestats (size SMALLINT, villagewins SMALLINT, ' +
|
('CREATE TABLE IF NOT EXISTS gamestats (size SMALLINT, villagewins SMALLINT, ' +
|
||||||
'wolfwins SMALLINT, totalgames SMALLINT, UNIQUE(size))'))
|
'wolfwins SMALLINT, totalgames SMALLINT, UNIQUE(size))'))
|
||||||
|
|
||||||
|
|
||||||
if OPT_IN_PING:
|
if OPT_IN_PING:
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS ping (cloak text)')
|
c.execute('CREATE TABLE IF NOT EXISTS ping (cloak text)')
|
||||||
|
|
||||||
@ -246,22 +262,27 @@ def remove_away(clk):
|
|||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from away where nick=?', (clk,))
|
c.execute('DELETE from away where nick=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_away(clk):
|
def add_away(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into away VALUES (?)', (clk,))
|
c.execute('INSERT into away VALUES (?)', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def remove_simple_rolemsg(clk):
|
def remove_simple_rolemsg(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from simple_role_notify where cloak=?', (clk,))
|
c.execute('DELETE from simple_role_notify where cloak=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_simple_rolemsg(clk):
|
def add_simple_rolemsg(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into simple_role_notify VALUES (?)', (clk,))
|
c.execute('INSERT into simple_role_notify VALUES (?)', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def remove_ping(clk):
|
def remove_ping(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('DELETE from ping where cloak=?', (clk,))
|
c.execute('DELETE from ping where cloak=?', (clk,))
|
||||||
|
|
||||||
|
|
||||||
def add_ping(clk):
|
def add_ping(clk):
|
||||||
with conn:
|
with conn:
|
||||||
c.execute('INSERT into ping VALUES (?)', (clk,))
|
c.execute('INSERT into ping VALUES (?)', (clk,))
|
||||||
@ -271,8 +292,10 @@ def update_role_stats(acc, role, won, iwon):
|
|||||||
with conn:
|
with conn:
|
||||||
wins, iwins, total = 0, 0, 0
|
wins, iwins, total = 0, 0, 0
|
||||||
|
|
||||||
c.execute(("SELECT teamwins, individualwins, totalgames FROM rolestats "+
|
c.execute(
|
||||||
"WHERE player=? AND role=?"), (acc, role))
|
("SELECT teamwins, individualwins, totalgames FROM rolestats " +
|
||||||
|
"WHERE player=? AND role=?"),
|
||||||
|
(acc, role))
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
if row:
|
if row:
|
||||||
wins, iwins, total = row
|
wins, iwins, total = row
|
||||||
@ -286,6 +309,7 @@ def update_role_stats(acc, role, won, iwon):
|
|||||||
c.execute("INSERT OR REPLACE INTO rolestats VALUES (?,?,?,?,?)",
|
c.execute("INSERT OR REPLACE INTO rolestats VALUES (?,?,?,?,?)",
|
||||||
(acc, role, wins, iwins, total))
|
(acc, role, wins, iwins, total))
|
||||||
|
|
||||||
|
|
||||||
def update_game_stats(size, winner):
|
def update_game_stats(size, winner):
|
||||||
with conn:
|
with conn:
|
||||||
vwins, wwins, total = 0, 0, 0
|
vwins, wwins, total = 0, 0, 0
|
||||||
@ -305,51 +329,81 @@ def update_game_stats(size, winner):
|
|||||||
c.execute("INSERT OR REPLACE INTO gamestats VALUES (?,?,?,?)",
|
c.execute("INSERT OR REPLACE INTO gamestats VALUES (?,?,?,?)",
|
||||||
(size, vwins, wwins, total))
|
(size, vwins, wwins, total))
|
||||||
|
|
||||||
|
|
||||||
def get_player_stats(acc, role):
|
def get_player_stats(acc, role):
|
||||||
if role.lower() not in ["villager"] + [v.lower() for k, v in ROLE_INDICES.items()]:
|
if role.lower() not in ["villager"] + [v.lower()
|
||||||
|
for k, v in ROLE_INDICES.items()]:
|
||||||
return "No such role: {0}".format(role)
|
return "No such role: {0}".format(role)
|
||||||
with conn:
|
with conn:
|
||||||
c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,))
|
c.execute(
|
||||||
|
"SELECT player FROM rolestats WHERE player=? COLLATE NOCASE",
|
||||||
|
(acc,))
|
||||||
player = c.fetchone()
|
player = c.fetchone()
|
||||||
if player:
|
if player:
|
||||||
for row in c.execute("SELECT * FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE", (acc, role)):
|
for row in c.execute("SELECT * FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE", (acc, role)):
|
||||||
msg = "\u0002{0}\u0002 as \u0002{1}\u0002 | Team wins: {2} (%d%%), Individual wins: {3} (%d%%), Total games: {4}".format(*row)
|
msg = "\u0002{0}\u0002 as \u0002{1}\u0002 | Team wins: {2} (%d%%), Individual wins: {3} (%d%%), Total games: {4}".format(
|
||||||
return msg % (round(row[2]/row[4] * 100), round(row[3]/row[4] * 100))
|
*
|
||||||
|
row)
|
||||||
|
return msg % (
|
||||||
|
round(row[2] / row[4] * 100),
|
||||||
|
round(row[3] / row[4] * 100))
|
||||||
else:
|
else:
|
||||||
return "No stats for {0} as {1}.".format(player[0], role)
|
return "No stats for {0} as {1}.".format(player[0], role)
|
||||||
return "{0} has not played any games.".format(acc)
|
return "{0} has not played any games.".format(acc)
|
||||||
|
|
||||||
|
|
||||||
def get_player_totals(acc):
|
def get_player_totals(acc):
|
||||||
role_totals = []
|
role_totals = []
|
||||||
with conn:
|
with conn:
|
||||||
c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,))
|
c.execute(
|
||||||
|
"SELECT player FROM rolestats WHERE player=? COLLATE NOCASE",
|
||||||
|
(acc,))
|
||||||
player = c.fetchone()
|
player = c.fetchone()
|
||||||
if player:
|
if player:
|
||||||
for role in ["villager"] + [v for k, v in ROLE_INDICES.items()]:
|
for role in ["villager"] + [v for k, v in ROLE_INDICES.items()]:
|
||||||
c.execute("SELECT totalgames FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE", (acc, role))
|
c.execute(
|
||||||
|
"SELECT totalgames FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE",
|
||||||
|
(acc, role))
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
if row:
|
if row:
|
||||||
role_totals.append("\u0002{0}\u0002: {1}".format(role, *row))
|
role_totals.append(
|
||||||
c.execute("SELECT SUM(totalgames) from rolestats WHERE player=? COLLATE NOCASE AND role!='cursed villager' AND role!='gunner'", (acc,))
|
"\u0002{0}\u0002: {1}".format(
|
||||||
|
role,
|
||||||
|
*
|
||||||
|
row))
|
||||||
|
c.execute(
|
||||||
|
"SELECT SUM(totalgames) from rolestats WHERE player=? COLLATE NOCASE AND role!='cursed villager' AND role!='gunner'",
|
||||||
|
(acc,))
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
return "\u0002{0}\u0002's totals | \u0002{1}\u0002 games | {2}".format(player[0], row[0], ", ".join(role_totals))
|
return "\u0002{0}\u0002's totals | \u0002{1}\u0002 games | {2}".format(
|
||||||
|
player[0],
|
||||||
|
row[0],
|
||||||
|
", ".join(role_totals))
|
||||||
else:
|
else:
|
||||||
return "\u0002{0}\u0002 has not played any games.".format(acc)
|
return "\u0002{0}\u0002 has not played any games.".format(acc)
|
||||||
|
|
||||||
|
|
||||||
def get_game_stats(size):
|
def get_game_stats(size):
|
||||||
with conn:
|
with conn:
|
||||||
for row in c.execute("SELECT * FROM gamestats WHERE size=?", (size,)):
|
for row in c.execute("SELECT * FROM gamestats WHERE size=?", (size,)):
|
||||||
msg = "\u0002{0}\u0002 player games | Village wins: {1} (%d%%), Wolf wins: {2} (%d%%), Total games: {3}".format(*row)
|
msg = "\u0002{0}\u0002 player games | Village wins: {1} (%d%%), Wolf wins: {2} (%d%%), Total games: {3}".format(
|
||||||
return msg % (round(row[1]/row[3] * 100), round(row[2]/row[3] * 100))
|
*
|
||||||
|
row)
|
||||||
|
return msg % (
|
||||||
|
round(row[1] / row[3] * 100),
|
||||||
|
round(row[2] / row[3] * 100))
|
||||||
else:
|
else:
|
||||||
return "No stats for \u0002{0}\u0002 player games.".format(size)
|
return "No stats for \u0002{0}\u0002 player games.".format(size)
|
||||||
|
|
||||||
|
|
||||||
def get_game_totals():
|
def get_game_totals():
|
||||||
size_totals = []
|
size_totals = []
|
||||||
total = 0
|
total = 0
|
||||||
with conn:
|
with conn:
|
||||||
for size in range(MIN_PLAYERS, MAX_PLAYERS + 1):
|
for size in range(MIN_PLAYERS, MAX_PLAYERS + 1):
|
||||||
c.execute("SELECT size, totalgames FROM gamestats WHERE size=?", (size,))
|
c.execute(
|
||||||
|
"SELECT size, totalgames FROM gamestats WHERE size=?",
|
||||||
|
(size,))
|
||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
if row:
|
if row:
|
||||||
size_totals.append("\u0002{0}p\u0002: {1}".format(*row))
|
size_totals.append("\u0002{0}p\u0002: {1}".format(*row))
|
||||||
|
@ -1,17 +1,30 @@
|
|||||||
# Copyright (c) 2011, Jimmy Cao
|
# Copyright (c) 2011, Jimmy Cao
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
|
||||||
# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
# Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
# Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
from oyoyo.parse import parse_nick
|
from oyoyo.parse import parse_nick
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import botconfig
|
import botconfig
|
||||||
|
|
||||||
|
|
||||||
def generate(fdict, permissions=True, **kwargs):
|
def generate(fdict, permissions=True, **kwargs):
|
||||||
"""Generates a decorator generator. Always use this"""
|
"""Generates a decorator generator. Always use this"""
|
||||||
def cmd(*s, raw_nick=False, admin_only=False, owner_only=False, hookid=-1):
|
def cmd(*s, raw_nick=False, admin_only=False, owner_only=False, hookid=-1):
|
||||||
@ -37,7 +50,9 @@ def generate(fdict, permissions=True, **kwargs):
|
|||||||
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
|
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
|
||||||
for cmdname in s:
|
for cmdname in s:
|
||||||
if cmdname in botconfig.DENY[pattern]:
|
if cmdname in botconfig.DENY[pattern]:
|
||||||
largs[0].notice(nick, "You do not have permission to use that command.")
|
largs[0].notice(
|
||||||
|
nick,
|
||||||
|
"You do not have permission to use that command.")
|
||||||
return
|
return
|
||||||
for pattern in botconfig.ALLOW.keys():
|
for pattern in botconfig.ALLOW.keys():
|
||||||
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
|
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
|
||||||
@ -45,15 +60,20 @@ def generate(fdict, permissions=True, **kwargs):
|
|||||||
if cmdname in botconfig.ALLOW[pattern]:
|
if cmdname in botconfig.ALLOW[pattern]:
|
||||||
return f(*largs) # no questions
|
return f(*largs) # no questions
|
||||||
if owner_only:
|
if owner_only:
|
||||||
if cloak and [ptn for ptn in botconfig.OWNERS
|
if cloak and [
|
||||||
if fnmatch.fnmatch(cloak.lower(), ptn.lower())]:
|
ptn for ptn in botconfig.OWNERS if fnmatch.fnmatch(
|
||||||
|
cloak.lower(),
|
||||||
|
ptn.lower())]:
|
||||||
return f(*largs)
|
return f(*largs)
|
||||||
elif cloak:
|
elif cloak:
|
||||||
largs[0].notice(nick, "You are not the owner.")
|
largs[0].notice(nick, "You are not the owner.")
|
||||||
return
|
return
|
||||||
if admin_only:
|
if admin_only:
|
||||||
if cloak and [ptn for ptn in botconfig.ADMINS+botconfig.OWNERS
|
if cloak and[ptn
|
||||||
if fnmatch.fnmatch(cloak.lower(), ptn.lower())]:
|
for ptn in botconfig.ADMINS + botconfig.OWNERS
|
||||||
|
if fnmatch.fnmatch(
|
||||||
|
cloak.lower(),
|
||||||
|
ptn.lower())]:
|
||||||
return f(*largs)
|
return f(*largs)
|
||||||
elif cloak:
|
elif cloak:
|
||||||
largs[0].notice(nick, "You are not an admin.")
|
largs[0].notice(nick, "You are not an admin.")
|
||||||
@ -68,7 +88,10 @@ def generate(fdict, permissions=True, **kwargs):
|
|||||||
for fn in fdict[x]:
|
for fn in fdict[x]:
|
||||||
if (fn.owner_only != owner_only or
|
if (fn.owner_only != owner_only or
|
||||||
fn.admin_only != admin_only):
|
fn.admin_only != admin_only):
|
||||||
raise Exception("Command: "+x+" has non-matching protection levels!")
|
raise Exception(
|
||||||
|
"Command: " +
|
||||||
|
x +
|
||||||
|
" has non-matching protection levels!")
|
||||||
fdict[x].append(innerf)
|
fdict[x].append(innerf)
|
||||||
if alias:
|
if alias:
|
||||||
innerf.aliases.append(x)
|
innerf.aliases.append(x)
|
||||||
@ -82,7 +105,8 @@ def generate(fdict, permissions=True, **kwargs):
|
|||||||
|
|
||||||
return dec
|
return dec
|
||||||
|
|
||||||
return lambda *args, **kwarargs: cmd(*args, **kwarargs) if kwarargs else cmd(*args, **kwargs)
|
return lambda *args, **kwarargs: cmd(*args, **
|
||||||
|
kwarargs) if kwarargs else cmd(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def unhook(hdict, hookid):
|
def unhook(hdict, hookid):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import botconfig
|
import botconfig
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class WolfgameLogger(object):
|
class WolfgameLogger(object):
|
||||||
|
|
||||||
def __init__(self, outfile, boutfile):
|
def __init__(self, outfile, boutfile):
|
||||||
@ -17,13 +18,16 @@ class WolfgameLogger(object):
|
|||||||
self.barelogged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + " ".join(args) + "\n"
|
self.barelogged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + " ".join(args) + "\n"
|
||||||
|
|
||||||
def logChannelMessage(self, who, message):
|
def logChannelMessage(self, who, message):
|
||||||
self.logged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + "<{0}> {1}\n".format(who, message)
|
self.logged += datetime.utcnow().strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S ") + "<{0}> {1}\n".format(who, message)
|
||||||
|
|
||||||
def logCommand(self, who, cmd, rest):
|
def logCommand(self, who, cmd, rest):
|
||||||
self.logged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + "<{0}> {1}{2} {3}".format(who, botconfig.CMD_CHAR, cmd, rest) + "\n"
|
self.logged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + \
|
||||||
|
"<{0}> {1}{2} {3}".format(who, botconfig.CMD_CHAR, cmd, rest) + "\n"
|
||||||
|
|
||||||
def logMessage(self, message):
|
def logMessage(self, message):
|
||||||
self.logged += datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + "<{0}> ".format(botconfig.NICK)+message+"\n"
|
self.logged += datetime.utcnow().strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S ") + "<{0}> ".format(botconfig.NICK) + message + "\n"
|
||||||
|
|
||||||
def saveToFile(self):
|
def saveToFile(self):
|
||||||
if self.outfile:
|
if self.outfile:
|
||||||
|
Loading…
Reference in New Issue
Block a user