Huge overhaul to the decorators + small changes.

- Merge channel and PM commands in a single decorator.
- Add many parameters for the decorators, reducing commands cluster.
- Added back the admin_only check for some commands; special-cased
'<console>'.
- Moved the checking for which roles are seen wolf in the settings; same
for seen as default.
- Added a variable to pick if one is seen as the default role or as a
villager where applicable (default: True).
- Fixed seer/oracle seeing through amnesiac.
- Some fixes to the totem chances that I forgot to add in the previous
commit.
- Removed some useless module imports.
- Moved some functions to settings.
- Changed all single-quotes to double-quotes in commands for
consistency.
- Renamed 'cmd' variable in both force and rforce commands to avoid
confusion.
- Probably a bunch of other things. Don't consider this commit
description to be 100% complete.
This commit is contained in:
Vgr E.Barry 2014-12-31 09:33:06 -05:00
parent 53cf4970ca
commit df26d8d25e
4 changed files with 443 additions and 812 deletions

View File

@ -7,6 +7,7 @@ import tools.moduleloader as ld
import traceback
from settings import common as var
from base64 import b64encode
from oyoyo.parse import parse_nick
import imp
def on_privmsg(cli, rawnick, chan, msg, notice = False):
@ -19,50 +20,39 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
(chan == botconfig.NICK and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
return # not allowed in settings
if chan != botconfig.NICK: #not a PM
if currmod and "" in currmod.COMMANDS.keys():
for fn in currmod.COMMANDS[""]:
if chan == botconfig.NICK:
chan = parse_nick(rawnick)[0]
if currmod and "" in currmod.COMMANDS.keys():
for fn in currmod.COMMANDS[""]:
try:
fn(cli, rawnick, chan, msg)
except:
if botconfig.DEBUG_MODE:
raise
else:
logging.error(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.")
for x in set(list(COMMANDS.keys()) + (list(currmod.COMMANDS.keys()) if currmod else list())):
if chan != parse_nick(rawnick)[0] 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):]
elif not x or msg.lower().startswith(x):
h = msg[len(x):]
else:
continue
if not h or h[0] == " ":
for fn in COMMANDS.get(x, []) + (currmod.COMMANDS.get(x, []) if currmod else []):
try:
fn(cli, rawnick, chan, msg)
except Exception as e:
fn(cli, rawnick, chan, h.lstrip())
except:
if botconfig.DEBUG_MODE:
raise e
raise
else:
logging.error(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.")
# Now that is always called first.
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):
h = msg[len(x)+len(botconfig.CMD_CHAR):]
if not h or h[0] == " " or not x:
for fn in COMMANDS.get(x,[])+(currmod.COMMANDS.get(x,[]) if currmod else []):
try:
fn(cli, rawnick, chan, h.lstrip())
except Exception as e:
if botconfig.DEBUG_MODE:
raise e
else:
logging.error(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.")
else:
for x in set(list(PM_COMMANDS.keys()) + (list(currmod.PM_COMMANDS.keys()) if currmod else list())):
if msg.lower().startswith(botconfig.CMD_CHAR+x):
h = msg[len(x)+len(botconfig.CMD_CHAR):]
elif not x or msg.lower().startswith(x):
h = msg[len(x):]
else:
continue
if not h or h[0] == " " or not x:
for fn in PM_COMMANDS.get(x, [])+(currmod.PM_COMMANDS.get(x,[]) if currmod else []):
try:
fn(cli, rawnick, h.lstrip())
except Exception as e:
if botconfig.DEBUG_MODE:
raise e
else:
logging.error(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.")
def __unhandled__(cli, prefix, cmd, *args):
currmod = ld.MODULES[ld.CURRENT_MODULE]
@ -87,11 +77,9 @@ def __unhandled__(cli, prefix, cmd, *args):
COMMANDS = {}
PM_COMMANDS = {}
HOOKS = {}
cmd = decorators.generate(COMMANDS)
pmcmd = decorators.generate(PM_COMMANDS)
hook = decorators.generate(HOOKS, raw_nick=True, permissions=False)
def connect_callback(cli):

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,7 @@ START_WITH_DAY = False
WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets
ROLE_REVEAL = True
LOVER_WINS_WITH_FOOL = False # if fool is lynched, does their lover win with them?
DEFAULT_SEEN_AS_VILL = True # non-wolves are seen as villager regardless of the default role
# Minimum number of players needed for mad scientist to skip over dead people when determining who is next to them
# Set to 0 to always skip over dead players. Note this is number of players that !joined, NOT number of players currently alive
@ -180,13 +181,17 @@ ROLE_GUIDE = {# village roles
# If every wolf role dies, and there are no remaining traitors, the game ends and villagers win (monster may steal win)
WOLF_ROLES = ["wolf", "alpha wolf", "werecrow", "wolf cub"]
# Access to wolfchat, and counted towards the # of wolves vs villagers when determining if a side has won
WOLFCHAT_ROLES = ["wolf", "alpha wolf", "werecrow", "wolf cub", "traitor", "hag", "sorcerer"]
WOLFCHAT_ROLES = WOLF_ROLES + ["traitor", "hag", "sorcerer"]
# Wins with the wolves, even if the roles are not necessarily wolves themselves
WOLFTEAM_ROLES = ["wolf", "alpha wolf", "werecrow", "wolf cub", "traitor", "hag", "sorcerer", "minion", "cultist"]
WOLFTEAM_ROLES = WOLFCHAT_ROLES + ["minion", "cultist"]
# These roles never win as a team, only ever individually (either instead of or in addition to the regular winners)
TRUE_NEUTRAL_ROLES = ["crazed shaman", "fool", "jester", "monster", "clone"]
# These are the roles that will NOT be used for when amnesiac turns, everything else is fair game! (var.DEFAULT_ROLE is also appended if not in this list)
AMNESIAC_BLACKLIST = ["monster", "amnesiac", "minion", "matchmaker", "clone", "doctor", "villager", "cultist"]
# These roles are seen as wolf by the seer/oracle
SEEN_WOLF = WOLF_ROLES + ["monster", "mad scientist"]
# These are seen as the default role (or villager) when seen by seer
SEEN_DEFAULT = ["traitor", "hag", "sorcerer", "village elder", "time lord", "villager", "cultist", "minion", "vengeful ghost", "lycan", "clone", "fool", "jester"]
# The roles in here are considered templates and will be applied on TOP of other roles. The restrictions are a list of roles that they CANNOT be applied to
# NB: if you want a template to apply to everyone, list it here but make the restrictions an empty list. Templates not listed here are considered full roles instead
@ -223,7 +228,7 @@ QUIT_MESSAGES_NO_REVEAL = ("\u0002{0}\u0002 suddenly falls over dead before the
"\u0002{0}\u0002 fell off the roof of their house and is now dead.",
"\u0002{0}\u0002 is crushed to death by a falling tree. The villagers desperately try to save them, but it is too late.")
import botconfig, fnmatch
import botconfig, fnmatch, sys, time, re
RULES = (botconfig.CHANNEL + " channel rules: http://wolf.xnrand.com/rules")
DENY = {}
@ -240,6 +245,32 @@ PING_IN_ACCS = [] # accounts of people who have opted in for ping
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
def pm(cli, target, message): # message either privmsg or notice, depending on user settings
if is_fake_nick(target) and botconfig.DEBUG_MODE:
print("[{0}] Would send message to fake nick {1}: {2}".format(
time.strftime("%d/%b/%Y %H:%M:%S"),
target,
message), file=sys.stderr)
return
if is_user_notice(target):
cli.notice(target, message)
return
cli.msg(target, message)
def is_user_notice(nick):
if nick in USERS and USERS[nick]["account"] and USERS[nick]["account"] != "*":
if USERS[nick]["account"] in PREFER_NOTICE_ACCS:
return True
if nick in USERS and USERS[nick]["cloak"] in PREFER_NOTICE and not ACCOUNTS_ONLY:
return True
return False
def is_fake_nick(who):
return re.match("[0-9]+", who)
def is_admin(nick):
if nick not in USERS.keys():
return False

View File

@ -15,7 +15,8 @@ import settings.wolfgame as var
def generate(fdict, permissions=True, **kwargs):
"""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, chan=True, pm=False,
game=False, join=False, none=False, playing=False, roles=(), hookid=-1):
def dec(f):
def innerf(*args):
largs = list(args)
@ -29,13 +30,15 @@ def generate(fdict, permissions=True, **kwargs):
else:
nick = ""
cloak = ""
if len(largs) > 3 and largs[2] and largs[2][0] == "#":
chan = largs[2]
else:
chan = ""
if not raw_nick and len(largs) > 1 and largs[1]:
largs[1] = nick
if chan and not chan == botconfig.CHANNEL and not admin_only and not owner_only:
if nick == "<console>":
return f(*largs) # special case; no questions
if not pm and largs[2] == nick: # PM command
return
if not chan and largs[2] != nick: # channel command
return
if largs[2].startswith("#") and largs[2] != botconfig.CHANNEL and not admin_only and not owner_only:
if "" in s:
return # Don't have empty commands triggering in other channels
allowed = False
@ -51,6 +54,33 @@ def generate(fdict, permissions=True, **kwargs):
acc = None
if "" in s:
return f(*largs)
if game and var.PHASE not in ("day", "night") + (("join",) if join else ()):
largs[0].notice(nick, "No game is currently running.")
return
if ((join and none and var.PHASE not in ("join", "none"))
or (none and not join and var.PHASE != "none")):
largs[0].notice(nick, "Sorry, but the game is already running. Try again next time.")
return
if join and not none:
if var.PHASE == "none":
largs[0].notice(nick, "No game is currently running.")
return
if var.PHASE != "join" and not game:
largs[0].notice(nick, "Werewolf is already in play.")
return
if playing and nick not in var.list_players() or nick in var.DISCONNECTED.keys():
cli.notice(nick, "You're not currently playing.")
return
if roles:
for role in roles:
if nick in var.ROLES[role]:
break
else:
if len(roles) == 1:
var.pm(largs[0], nick, "Only a{0} {1} may use this command.".format("n" if roles[0][0] in "aeiou" else "", roles[0]))
else:
var.pm(largs[0], nick, "Only a{0} {1} or {2} may use this command.".format("n" if roles[0][0] in "aeiou" else "", ", ".join(roles[:-1]), roles[-1]))
return
if acc:
for pattern in var.DENY_ACCOUNTS.keys():
if fnmatch.fnmatch(acc.lower(), pattern.lower()):
@ -105,6 +135,13 @@ def generate(fdict, permissions=True, **kwargs):
innerf.owner_only = owner_only
innerf.raw_nick = raw_nick
innerf.admin_only = admin_only
innerf.chan = chan
innerf.pm = pm
innerf.none = none
innerf.join = join
innerf.game = game
innerf.playing = playing
innerf.roles = roles
innerf.hookid = hookid
innerf.__doc__ = f.__doc__
return innerf