From 5132d0a478844cd985987e2b1d7088fc4c8ae30f Mon Sep 17 00:00:00 2001 From: jcao219 Date: Mon, 4 Jul 2011 20:39:00 -0500 Subject: [PATCH] improved admin-only command setting, removed extra junk, added !wait + start time wait. --- decorators.py | 14 ++-- oyoyo/client.py | 94 +-------------------------- oyoyo/parse.py | 10 +-- vars.py | 13 +++- wolfgame.py | 167 ++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 162 insertions(+), 136 deletions(-) diff --git a/decorators.py b/decorators.py index 4d636f3..459905a 100644 --- a/decorators.py +++ b/decorators.py @@ -1,14 +1,20 @@ from oyoyo.parse import parse_nick +import botconfig; def generate(fdict): - def cmd(s, raw_nick=False): + def cmd(s, raw_nick=False, admin_only=False): def dec(f): def innerf(*args): largs = list(args) - largs[1] = parse_nick(largs[1])[0] + if not raw_nick: largs[1] = parse_nick(largs[1])[0] + if admin_only: + if largs[1] in botconfig.ADMINS: + return f(*largs) + else: + largs[0].notice(largs[1], "You are not an admin.") + return return f(*largs) - if raw_nick: fdict[s] = f - else: fdict[s] = innerf + fdict[s] = innerf return f return dec return cmd \ No newline at end of file diff --git a/oyoyo/client.py b/oyoyo/client.py index cd6da60..fef9a82 100644 --- a/oyoyo/client.py +++ b/oyoyo/client.py @@ -17,18 +17,9 @@ import logging import socket -import sys -import re -import string -import time -import threading -import os -import traceback -from oyoyo.parse import * +from oyoyo.parse import parse_raw_irc_command from oyoyo.cmdhandler import CommandError -import collections - class IRCClientError(Exception): pass @@ -201,89 +192,6 @@ class IRCClient: self.send("USER", uname, self.host, self.host, rname or uname) -class IRCApp: - """ This class manages several IRCClient instances without the use of threads. - (Non-threaded) Timer functionality is also included. - """ - - class _ClientDesc: - def __init__(self, **kwargs): - self.con = None - self.autoreconnect = False - self.__dict__.update(kwargs) - - def __init__(self): - self._clients = {} - self._timers = [] - self.running = False - self.sleep_time = 0.5 - - def addClient(self, client, autoreconnect=False): - """ add a client object to the application. setting autoreconnect - to true will mean the application will attempt to reconnect the client - after every disconnect. you can also set autoreconnect to a number - to specify how many reconnects should happen. - - warning: if you add a client that has blocking set to true, - timers will no longer function properly """ - logging.info('added client %s (ar=%s)' % (client, autoreconnect)) - self._clients[client] = self._ClientDesc(autoreconnect=autoreconnect) - - def addTimer(self, seconds, cb): - """ add a timed callback. accuracy is not specified, you can only - garuntee the callback will be called after seconds has passed. - ( the only advantage to these timers is they dont use threads ) - """ - assert isinstance(cb, collections.Callable) - logging.info('added timer to call %s in %ss' % (cb, seconds)) - self._timers.append((time.time() + seconds, cb)) - - def run(self): - """ run the application. this will block until stop() is called """ - # TODO: convert this to use generators too? - self.running = True - while self.running: - found_one_alive = False - - for client, clientdesc in self._clients.items(): - if clientdesc.con is None: - clientdesc.con = client.connect() - - try: - next(clientdesc.con) - except Exception as e: - logging.error('client error %s' % e) - logging.error(traceback.format_exc()) - if clientdesc.autoreconnect: - clientdesc.con = None - if isinstance(clientdesc.autoreconnect, (int, float)): - clientdesc.autoreconnect -= 1 - found_one_alive = True - else: - clientdesc.con = False - else: - found_one_alive = True - - if not found_one_alive: - logging.info('nothing left alive... quiting') - self.stop() - - now = time.time() - timers = self._timers[:] - self._timers = [] - for target_time, cb in timers: - if now > target_time: - logging.info('calling timer cb %s' % cb) - cb() - else: - self._timers.append((target_time, cb)) - - time.sleep(self.sleep_time) - - def stop(self): - """ stop the application """ - self.running = False - diff --git a/oyoyo/parse.py b/oyoyo/parse.py index 767a617..6b0dea5 100644 --- a/oyoyo/parse.py +++ b/oyoyo/parse.py @@ -16,15 +16,9 @@ # THE SOFTWARE. import logging -import sys -from oyoyo.ircevents import * - -# Python < 3 compatibility -if sys.version_info < (3,): - class bytes(object): - def __new__(self, b='', encoding='utf8'): - return str(b) +from oyoyo.ircevents import generated_events, protocol_events,\ + all_events, numeric_events def parse_raw_irc_command(element): diff --git a/vars.py b/vars.py index ef7e411..b339c86 100644 --- a/vars.py +++ b/vars.py @@ -1,12 +1,19 @@ +PING_WAIT = 300 # Seconds +MINIMUM_WAIT = 60 +EXTRA_WAIT = 20 +MAXIMUM_WAITED = 2 # limit for amount of !wait's +MAX_SHOTS = 2 + +# These change ingame ROLES = {"person" : []} ORIGINAL_ROLES = None PHASE = "none" # "join", "day", or "night" LAST_PING = 0 -PING_WAIT = 300 # Seconds -WAIT = 60 +CURSED = "" # nickname of cursed villager +GAME_START_TIME = 0 +CAN_START_TIME = 0 WAITED = 0 GUNNERS = {} -MAX_SHOTS = 2 is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol] diff --git a/wolfgame.py b/wolfgame.py index 2596907..d4f1bd3 100644 --- a/wolfgame.py +++ b/wolfgame.py @@ -2,6 +2,8 @@ from oyoyo.parse import parse_nick import vars import botconfig import decorators +import time +import random COMMANDS = {} PM_COMMANDS = {} @@ -17,7 +19,6 @@ def connect_callback(cli): cli.identify(botconfig.PASS) cli.join(botconfig.CHANNEL) cli.msg("ChanServ", "op "+botconfig.CHANNEL) - cli.msg(botconfig.CHANNEL, "\u0002Wolfbot2 is here.\u0002") def reset_game(): vars.ROLES = {"person" : []} @@ -29,12 +30,12 @@ def say(cli, nick, rest): # To be removed later cli.msg(botconfig.CHANNEL, "{0} says: {1}".format(nick, rest)) -@pmcmd("!bye") -@cmd("!bye") +@pmcmd("!bye", admin_only=True) +@cmd("!bye", admin_only=True) def forced_exit(cli, nick, *rest): # Admin Only - if nick in botconfig.ADMINS: - cli.quit("Forced quit from admin") - raise SystemExit + reset_game(cli, nick, rest[0], None) + cli.quit("Forced quit from admin") + raise SystemExit @cmd("!exec") def py(cli, nick, chan, rest): @@ -71,55 +72,165 @@ def pinger(cli, nick, chan, rest): @cmd("!join") def join(cli, nick, chan, rest): if vars.PHASE == "none": + cli.mode(chan, "+v", nick, nick+"!*@*") vars.ROLES["person"].append(nick) vars.PHASE = "join" + vars.CAN_START_TIME = time.time() + vars.MINIMUM_WAIT cli.msg(chan, '\u0002{0}\u0002 has started a game of Werewolf. \ Type "!join" to join. Type "!start" to start the game. \ Type "!wait" to increase join wait time.'.format(nick)) - elif nick in list_players(): + elif nick in vars.list_players(): cli.notice(nick, "You're already playing!") elif vars.PHASE != "join": cli.notice(nick, "Sorry but the game is already running. Try again next time.") else: + cli.mode(chan, "+v", nick, nick+"!*@*") vars.ROLES["person"].append(nick) cli.msg(chan, '\u0002{0}\u0002 has joined the game.'.format(nick)) @cmd("!stats") def stats(cli, nick, chan, rest): if vars.PHASE == "none": + cli.notice(nick, "No game is currently running.") return - pl = list_players() + + pl = vars.list_players() if len(pl) > 1: - cli.msg(chan, '{0}: {1} players: {2}'.format(nick, + cli.msg(chan, '{0}: \u0002{1}\u0002 players: {2}'.format(nick, len(pl), ", ".join(pl))) else: - cli.msg(chan, '{0}: 1 player: {1}'.format(nick, pl[0])) + cli.msg(chan, '{0}: \u00021\u0002 player: {1}'.format(nick, pl[0])) if vars.PHASE == "join": return - msg = [] - for role in vars.ROLES.keys(): - num = len(vars.ROLES[role]) - if num > 1: - msg.append("{0} {1}".format(num, plural(role))) + message = [] + for role in ("wolf", "seer", "harlot"): + count = len(vars.ROLES.get(role,[])) + if count > 1: + message.append("\u0002(0}\u0002 {1}".format(count, vars.plural(role))) else: - msg.append("{0} {1}".format(num, role)) - if len(msg) > 2: # More than 2 roles to say - msg[-1] = "and "+msg[-1]+"." - msg[0] = "{0}: There are ".format(nick) + msg[0] - cli.msg(chan, ", ".join(msg)) - elif len(msg) == 2: # 2 roles to say - cli.msg(chan, "{0}: There are ".format(nick) + msg[0], - "and", msg[1] + ".") - elif len(msg) == 1: - cli.msg(chan, "{0}: There is ".format(nick) + msg[0] + ".") + message.append("\u0002{0}\u0002 {1}".format(count, role)) + cli.msg(chan, + "{0}: There are {1}, and {2}.".format(nick, + ", ".join(message[0:-1]), + message[-1])) +def transition_night(cli, chan): + vars.PHASE = "night" + @cmd("!start") def start(cli, nick, chan, rest): - pl = list_players() - - if(len(pl)) < 4: + pl = vars.list_players() + if vars.PHASE == "none": + cli.notice(nick, "No game is currently running.") + return + if vars.PHASE != "join": + cli.notice(nick, "Werewolf is already in play.") + return + if nick not in pl: + cli.notice(nick, "You're currently not playing.") + return + now = time.time() + if vars.CAN_START_TIME > now: + cli.msg(chan, "Please wait at least {0} more seconds.".format( + int(vars.CAN_START_TIME - now))) + return + + if len(pl) < 4: cli.msg(chan, "{0}: Four or more players are required to play.".format(nick)) return + + vars.ROLES = {} + nharlots = 0 + nseers = 0 + nwolves = 0 + ndrunk = 0 + ncursed = 0 + + if len(pl) >= 8: + nharlots = 1 + nseers = 1 + nwolves = 2 + ndrunk = 1 + ncursed = 1 + elif(len(pl)) >= 6: + nseers = 1 + nwolves = 1 + ndrunk = 1 + ncursed = 1 + else: + nseers = 1 + nwolves = 1 + + seer = random.choice(pl) + vars.ROLES["seer"] = [seer] + pl.remove(seer) + if nharlots: + harlots = random.sample(pl, nharlots) + vars.ROLES["harlot"] = harlots + for h in harlots: + pl.remove(h) + if nwolves: + wolves = random.sample(pl, nwolves) + vars.ROLES["wolf"] = wolves + for w in wolves: + pl.remove(w) + if ndrunk: + drunk = random.choice(pl) + vars.ROLES["village drunk"] = [drunk] + pl.remove(drunk) + vars.ROLES["villager"] = pl + + if ncursed: + CURSED = random.choice(var.ROLES["villager"] + \ + var.ROLES.get("harlot", []) +\ + var.ROLES.get("village drunk", [])) + + cli.msg(chan, "{0}: Welcome to Werewolf, the popular detective/social \ +party game (a theme of Mafia).".format(", ".join(vars.list_players()))) + cli.mode(chan, "+m") + + vars.ORIGINAL_ROLES = dict(vars.ROLES) # Make a copy + transition_night(cli, chan) + +@cmd("!wait") +def wait(cli, nick, chan, rest): + pl = vars.list_players() + if vars.PHASE == "none": + cli.notice(nick, "No game is currently running.") + return + if vars.PHASE != "join": + cli.notice(nick, "Werewolf is already in play.") + return + if nick not in pl: + cli.notice(nick, "You're currently not playing.") + return + if vars.WAITED >= vars.MAXIMUM_WAITED: + cli.msg(chan, "Limit has already been reached for extending the wait time.") + return + + now = time.time() + if now > vars.CAN_START_TIME: + vars.CAN_START_TIME = now + vars.EXTRA_WAIT + else: + vars.CAN_START_TIME += vars.EXTRA_WAIT + vars.WAITED += 1 + cli.msg(chan, "{0} increased the wait \ +time by {1} seconds.".format(nick, vars.EXTRA_WAIT)) + +@cmd("!reset", admin_only = True) +def reset_game(cli, nick, chan, rest): + vars.PHASE = "none" + cli.mode(chan, "-m") + for pl in vars.list_players(): + cli.mode(chan, "-v", pl) + + vars.ROLES = {"person" : []} + vars.ORIGINAL_ROLES = None + vars.CURSED = "" + vars.GAME_START_TIME = 0 + vars.CAN_START_TIME = 0 + vars.GUNNERS = {} + vars.WAITED = 0 \ No newline at end of file