From 38edcffdb176f2965e225508e91c5a8bb58b49db Mon Sep 17 00:00:00 2001 From: Jimmy Cao Date: Wed, 28 Dec 2011 17:44:11 -0600 Subject: [PATCH] major restructuring --HG-- rename : wolfgame.py => modules/wolfgame.py rename : var.py => settings/wolfgame.py rename : decorators.py => tools/decorators.py rename : wolfgamelogger.py => tools/wolfgamelogger.py --- modules/__init__.py | 0 modules/common.py | 132 +++++++++++++++++++ modules/sabotage.py | 47 +++++++ wolfgame.py => modules/wolfgame.py | 76 +++-------- settings/__init__.py | 0 settings/sabotage.py | 6 + var.py => settings/wolfgame.py | 2 +- tools/__init__.py | 0 decorators.py => tools/decorators.py | 0 tools/moduleloader.py | 22 ++++ wolfgamelogger.py => tools/wolfgamelogger.py | 2 +- wolfbot.py | 72 +--------- 12 files changed, 233 insertions(+), 126 deletions(-) create mode 100644 modules/__init__.py create mode 100644 modules/common.py create mode 100644 modules/sabotage.py rename wolfgame.py => modules/wolfgame.py (98%) create mode 100644 settings/__init__.py create mode 100644 settings/sabotage.py rename var.py => settings/wolfgame.py (99%) create mode 100644 tools/__init__.py rename decorators.py => tools/decorators.py (100%) create mode 100644 tools/moduleloader.py rename wolfgamelogger.py => tools/wolfgamelogger.py (97%) diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/common.py b/modules/common.py new file mode 100644 index 0000000..1740421 --- /dev/null +++ b/modules/common.py @@ -0,0 +1,132 @@ +import botconfig +from tools import decorators +import logging +import tools.moduleloader as ld + + +def on_privmsg(cli, rawnick, chan, msg): + currmod = ld.MODULES[ld.CURRENT_MODULE] + + if chan != botconfig.NICK: #not a PM + if "" in currmod.COMMANDS.keys(): + for fn in currmod.COMMANDS[""]: + try: + fn(cli, rawnick, chan, msg) + 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.") + # Now that is always called first. + for x in set(list(COMMANDS.keys()) + list(currmod.COMMANDS.keys())): + if x and msg.lower().startswith(botconfig.CMD_CHAR+x): + h = msg[len(x)+1:] + if not h or h[0] == " " or not x: + for fn in COMMANDS.get(x,[])+currmod.COMMANDS.get(x,[]): + 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 msg.lower().startswith(botconfig.CMD_CHAR+x): + h = msg[len(x)+1:] + 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,[]): + 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] + if cmd in set(list(HOOKS.keys())+list(currmod.HOOKS.keys())): + largs = list(args) + for i,arg in enumerate(largs): + if isinstance(arg, bytes): largs[i] = arg.decode('ascii') + for fn in HOOKS.get(cmd, [])+currmod.HOOKS.get(cmd, []): + try: + fn(cli, prefix, *largs) + except Exception as e: + if botconfig.DEBUG_MODE: + raise e + else: + logging.error(traceback.format_exc()) + cli.msg(botconfig.CHANNEL, "An error has occurred and has been logged.") + else: + logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8') + for arg in args + if isinstance(arg, bytes)])) + + +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): + + def prepare_stuff(*args): + cli.join(botconfig.CHANNEL) + cli.msg("ChanServ", "op "+botconfig.CHANNEL) + + cli.cap("REQ", "extended-join") + cli.cap("REQ", "account-notify") + + ld.MODULES[ld.CURRENT_MODULE].connect_callback(cli) + + if botconfig.JOIN_AFTER_CLOAKED: + prepare_stuff = hook("event_hosthidden", id=294)(prepare_stuff) + + + @hook("nicknameinuse") + def mustghost(cli, *blah): + cli.nick(botconfig.NICK+"_") + cli.ns_ghost() + cli.nick(botconfig.NICK) + prepare_stuff(cli) + + @hook("unavailresource") + def mustrelease(cli, *blah): + cli.nick(botconfig.NICK+"_") + cli.ns_release() + cli.nick(botconfig.NICK) + prepare_stuff(cli) + + if not botconfig.JOIN_AFTER_CLOAKED: # join immediately + prepare_stuff(cli) + + + +@hook("ping") +def on_ping(cli, prefix, server): + cli.send('PONG', server) + + + +@cmd("module") +def ch_module(cli, nick, chan, rest): + rest = rest.strip() + if rest in ld.MODULES.keys(): + ld.CURRENT_MODULE = rest + ld.MODULES[rest].connect_callback(cli) + cli.msg(chan, "Module {0} is now active.".format(rest)) + else: + cli.msg(chan, "Module {0} does not exist.".format(rest)) diff --git a/modules/sabotage.py b/modules/sabotage.py new file mode 100644 index 0000000..680debe --- /dev/null +++ b/modules/sabotage.py @@ -0,0 +1,47 @@ +from tools import decorators +import settings.sabotage as var +import time +from datetime import datetime, timedelta +import botconfig + +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): + var.PHASE = "none" + var.PLAYERS = [] + + +@cmd("join") +def join(cli, nick, chan, rest): + """Either starts a new game of Werewolf or joins an existing game that has not started yet.""" + + if var.PHASE == "none": + + cli.mode(chan, "+v", nick, nick+"!*@*") + var.PLAYERS.append(nick) + var.PHASE = "join" + var.WAITED = 0 + var.GAME_ID = time.time() + var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT) + cli.msg(chan, ('\u0002{0}\u0002 has started a game of Sabotage. '+ + 'Type "{1}join" to join. Type "{1}start" to start the game. '+ + 'Type "{1}wait" to increase join wait time.').format(nick, botconfig.CMD_CHAR)) + elif nick in var.PLAYERS: + cli.notice(nick, "You're already playing!") + elif len(pl) >= var.MAX_PLAYERS: + cli.notice(nick, "Too many players! Try again next time.") + elif var.PHASE != "join": + cli.notice(nick, "Sorry but the game is already running. Try again next time.") + else: + + cli.mode(chan, "+v", nick, nick+"!*@*") + var.PLAYERS.append(nick) + cli.msg(chan, '\u0002{0}\u0002 has joined the game.'.format(nick)) + + var.LAST_STATS = None # reset diff --git a/wolfgame.py b/modules/wolfgame.py similarity index 98% rename from wolfgame.py rename to modules/wolfgame.py index e96486c..f9f109a 100644 --- a/wolfgame.py +++ b/modules/wolfgame.py @@ -8,10 +8,10 @@ # 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 -import var +import settings.wolfgame as var import botconfig -from wolfgamelogger import WolfgameLogger -import decorators +from tools.wolfgamelogger import WolfgameLogger +from tools import decorators from datetime import datetime, timedelta import threading import random @@ -37,46 +37,22 @@ hook = decorators.generate(HOOKS, raw_nick=True, permissions=False) def connect_callback(cli): - def prepare_stuff(*args): - cli.join(botconfig.CHANNEL) - cli.msg("ChanServ", "op "+botconfig.CHANNEL) - - @hook("whospcrpl", id=294) - def on_whoreply(cli, server, nick, ident, cloak, user, acc): - if user in var.USERS: return # Don't add someone who is already there - if user == botconfig.NICK: - cli.nickname = user - cli.ident = ident - cli.hostmask = cloak - if acc == "0": - acc = "*" - var.USERS[user] = dict(cloak=cloak,account=acc) - - @hook("endofwho", id=294) - def afterwho(*args): - decorators.unhook(HOOKS, 294) - - cli.cap("REQ", "extended-join") - cli.cap("REQ", "account-notify") - - cli.who(botconfig.CHANNEL, "%nuha") - if botconfig.JOIN_AFTER_CLOAKED: - prepare_stuff = hook("event_hosthidden", id=294)(prepare_stuff) + @hook("whospcrpl", id=294) + def on_whoreply(cli, server, nick, ident, cloak, user, acc): + if user in var.USERS: return # Don't add someone who is already there + if user == botconfig.NICK: + cli.nickname = user + cli.ident = ident + cli.hostmask = cloak + if acc == "0": + acc = "*" + var.USERS[user] = dict(cloak=cloak,account=acc) - - @hook("nicknameinuse") - def mustghost(cli, *blah): - cli.nick(botconfig.NICK+"_") - cli.ns_ghost() - cli.nick(botconfig.NICK) - prepare_stuff(cli) - - @hook("unavailresource") - def mustrelease(cli, *blah): - cli.nick(botconfig.NICK+"_") - cli.ns_release() - cli.nick(botconfig.NICK) - prepare_stuff(cli) + @hook("endofwho", id=294) + def afterwho(*args): + decorators.unhook(HOOKS, 294) + + cli.who(botconfig.CHANNEL, "%nuha") var.LAST_PING = None # time of last ping var.LAST_STATS = None @@ -116,9 +92,6 @@ def connect_callback(cli): var.DAY_TIME_LIMIT_CHANGE = 0 var.KILL_IDLE_TIME = 0 #300 var.WARN_IDLE_TIME = 0 #180 - - if not botconfig.JOIN_AFTER_CLOAKED: # join immediately - prepare_stuff(cli) @@ -784,7 +757,7 @@ def chk_win(cli): if lwolves == lpl / 2: cli.msg(chan, ("Game over! There are the same number of wolves as "+ - "villagers. The wolves eat everyone, and win.")) + "villagers. The wolves eat everyone and win.")) var.LOGGER.logMessage(("Game over! There are the same number of wolves as "+ "villagers. The wolves eat everyone, and win.")) village_win = False @@ -885,12 +858,7 @@ def del_player(cli, nick, forced_death = False): if nick in var.WOUNDED: var.WOUNDED.remove(nick) chk_decision(cli) - return ret - - -@hook("ping") -def on_ping(cli, prefix, server): - cli.send('PONG', server) + return ret def reaper(cli, gameid): @@ -980,8 +948,6 @@ def on_join(cli, raw_nick, chan, acc="*", rname=""): break if nick in var.DCED_PLAYERS.keys(): var.PLAYERS[nick] = var.DCED_PLAYERS.pop(nick) - with open("returned.log", "a") as logf: - logf.write(time.strftime("%d/%b/%Y %H:%M:%S ", time.gmtime())+nick+"\n") @cmd("goat") def goat(cli, nick, chan, rest): @@ -1107,8 +1073,6 @@ def on_nick(cli, prefix, nick): cli.msg(chan, ("\02{0}\02 has returned to "+ "the village.").format(nick)) - with open("returned.log", "a") as logf: - logf.write(time.strftime("%d/%b/%Y %H:%M:%S ", time.gmtime())+nick+"\n") def leave(cli, what, nick, why=""): nick, _, _, cloak = parse_nick(nick) diff --git a/settings/__init__.py b/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/settings/sabotage.py b/settings/sabotage.py new file mode 100644 index 0000000..fdcc7c6 --- /dev/null +++ b/settings/sabotage.py @@ -0,0 +1,6 @@ +MINIMUM_WAIT = 60 # seconds before game can be started +EXTRA_WAIT = 20 +MAXIMUM_WAITED = 2 # number of times !wait can be used + +MAX_PLAYERS = 5 +MIN_PLAYERS = 5 diff --git a/var.py b/settings/wolfgame.py similarity index 99% rename from var.py rename to settings/wolfgame.py index b7b4e64..008cae1 100644 --- a/var.py +++ b/settings/wolfgame.py @@ -18,7 +18,7 @@ PART_GRACE_TIME = 7 QUIT_GRACE_TIME = 30 LOG_FILENAME = "" -BARE_LOG_FILENAME = "barelog.txt" +BARE_LOG_FILENAME = "" # HIT MISS SUICIDE GUN_CHANCES = ( 5/7 , 1/7 , 1/7 ) diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/decorators.py b/tools/decorators.py similarity index 100% rename from decorators.py rename to tools/decorators.py diff --git a/tools/moduleloader.py b/tools/moduleloader.py new file mode 100644 index 0000000..10f802d --- /dev/null +++ b/tools/moduleloader.py @@ -0,0 +1,22 @@ +import os +import botconfig + +MODULES = {} + +for modfile in os.listdir("modules"): + if modfile == "common.py": + continue # no need to load this one + if modfile.startswith("__"): + continue + if not modfile.endswith(".py"): + continue # not a module + if not os.path.isfile("modules/"+modfile): + continue # not a file + + modfile = modfile[:-3] + MODULES[modfile] = getattr(__import__("modules."+modfile), modfile) + +if botconfig.DEFAULT_MODULE in MODULES.keys(): + CURRENT_MODULE = botconfig.DEFAULT_MODULE.lower() +else: + CURRENT_MODULE = "wolfgame" diff --git a/wolfgamelogger.py b/tools/wolfgamelogger.py similarity index 97% rename from wolfgamelogger.py rename to tools/wolfgamelogger.py index 379e6eb..f50918d 100644 --- a/wolfgamelogger.py +++ b/tools/wolfgamelogger.py @@ -35,4 +35,4 @@ class WolfgameLogger(object): bl.write(self.barelogged) self.logged = "" - self.barelogged = "" \ No newline at end of file + self.barelogged = "" diff --git a/wolfbot.py b/wolfbot.py index 356ab75..57d2745 100755 --- a/wolfbot.py +++ b/wolfbot.py @@ -23,77 +23,13 @@ from oyoyo.client import IRCClient from oyoyo.parse import parse_nick import logging import botconfig -import wolfgame import time import traceback +import modules.common class UTCFormatter(logging.Formatter): converter = time.gmtime -def on_privmsg(cli, rawnick, chan, msg): - if chan != botconfig.NICK: #not a PM - if "" in wolfgame.COMMANDS.keys(): - for fn in wolfgame.COMMANDS[""]: - try: - fn(cli, rawnick, chan, msg) - 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.") - # Now that is always called first. - for x in wolfgame.COMMANDS.keys(): - if x and msg.lower().startswith(botconfig.CMD_CHAR+x): - h = msg[len(x)+1:] - if not h or h[0] == " " or not x: - for fn in wolfgame.COMMANDS[x]: - 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 wolfgame.PM_COMMANDS.keys(): - if msg.lower().startswith(botconfig.CMD_CHAR+x): - h = msg[len(x)+1:] - 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 wolfgame.PM_COMMANDS[x]: - 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): - if cmd in wolfgame.HOOKS.keys(): - largs = list(args) - for i,arg in enumerate(largs): - if isinstance(arg, bytes): largs[i] = arg.decode('ascii') - for fn in wolfgame.HOOKS[cmd]: - try: - fn(cli, prefix, *largs) - except Exception as e: - if botconfig.DEBUG_MODE: - raise e - else: - logging.error(traceback.format_exc()) - cli.msg(botconfig.CHANNEL, "An error has occurred and has been logged.") - else: - logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8') - for arg in args - if isinstance(arg, bytes)])) - def main(): if not botconfig.DEBUG_MODE: logging.basicConfig(filename='errors.log', filemode='a', level=logging.WARNING) @@ -104,14 +40,14 @@ def main(): logging.basicConfig(level=logging.DEBUG) cli = IRCClient( - {"privmsg":on_privmsg, - "":__unhandled__}, + {"privmsg":modules.common.on_privmsg, + "":modules.common.__unhandled__}, host=botconfig.HOST, port=botconfig.PORT, authname=botconfig.USERNAME, password=botconfig.PASS, nickname=botconfig.NICK, - connect_cb=wolfgame.connect_callback + connect_cb=modules.common.connect_callback ) cli.mainLoop()