added a tokenbucket algo rate limiter, and added the detective role
This commit is contained in:
parent
d238c81fdc
commit
ad750d8f66
@ -17,12 +17,49 @@
|
||||
|
||||
import logging
|
||||
import socket
|
||||
import time
|
||||
|
||||
from oyoyo.parse import parse_raw_irc_command
|
||||
|
||||
class IRCClientError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# Adapted from http://code.activestate.com/recipes/511490-implementation-of-the-token-bucket-algorithm/
|
||||
class TokenBucket(object):
|
||||
"""An implementation of the token bucket algorithm.
|
||||
|
||||
>>> bucket = TokenBucket(80, 0.5)
|
||||
>>> bucket.consume(1)
|
||||
"""
|
||||
def __init__(self, tokens, fill_rate):
|
||||
"""tokens is the total tokens in the bucket. fill_rate is the
|
||||
rate in tokens/second that the bucket will be refilled."""
|
||||
self.capacity = float(tokens)
|
||||
self._tokens = float(tokens)
|
||||
self.fill_rate = float(fill_rate)
|
||||
self.timestamp = time.time()
|
||||
|
||||
def consume(self, tokens):
|
||||
"""Consume tokens from the bucket. Returns True if there were
|
||||
sufficient tokens otherwise False."""
|
||||
if tokens <= self.tokens:
|
||||
self._tokens -= tokens
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def tokens(self):
|
||||
if self._tokens < self.capacity:
|
||||
now = time.time()
|
||||
delta = self.fill_rate * (now - self.timestamp)
|
||||
self._tokens = min(self.capacity, self._tokens + delta)
|
||||
self.timestamp = now
|
||||
return self._tokens
|
||||
|
||||
|
||||
|
||||
def add_commands(d):
|
||||
def dec(cls):
|
||||
for c in d:
|
||||
@ -70,6 +107,7 @@ class IRCClient(object):
|
||||
self.port = None
|
||||
self.connect_cb = None
|
||||
self.blocking = True
|
||||
self.tokenbucket = TokenBucket(3, 7.3)
|
||||
|
||||
self.__dict__.update(kwargs)
|
||||
self.command_handler = cmd_handler
|
||||
@ -181,6 +219,8 @@ class IRCClient(object):
|
||||
self.socket.close()
|
||||
def msg(self, user, msg):
|
||||
for line in msg.split('\n'):
|
||||
while not self.tokenbucket.consume(1):
|
||||
time.sleep(1)
|
||||
self.send("PRIVMSG", user, ":{0}".format(line))
|
||||
privmsg = msg # Same thing
|
||||
def notice(self, user, msg):
|
||||
|
31
var.py
31
var.py
@ -18,18 +18,19 @@ MANSLAUGHTER_CHANCE = 1/5
|
||||
|
||||
GAME_MODES = {}
|
||||
|
||||
######################################################################################################
|
||||
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL ##
|
||||
######################################################################################################
|
||||
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0), ##
|
||||
6 : ( 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0), ##
|
||||
8 : ( 1 , 2 , 1 , 1 , 1 , 0 , 0 , 0 , 0), ##
|
||||
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0), ##
|
||||
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1), ##
|
||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0)} ##
|
||||
######################################################################################################
|
||||
# Notes: ##
|
||||
######################################################################################################
|
||||
#################################################################################################################
|
||||
# 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 ), ##
|
||||
6 : ( 1 , 1 , 1 , 1 , 0 , 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 ), ##
|
||||
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 ), ##
|
||||
15 : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
|
||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
|
||||
#################################################################################################################
|
||||
# Notes: ##
|
||||
#################################################################################################################
|
||||
|
||||
|
||||
ROLE_INDICES = {0 : "seer",
|
||||
@ -40,7 +41,8 @@ ROLE_INDICES = {0 : "seer",
|
||||
5 : "traitor",
|
||||
6 : "gunner",
|
||||
7 : "werecrow",
|
||||
8 : "guardian angel"}
|
||||
8 : "guardian angel",
|
||||
9 : "detective"}
|
||||
INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
|
||||
|
||||
|
||||
@ -98,7 +100,8 @@ CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"],
|
||||
"traitors" : INDEX_OF_ROLE["traitor"],
|
||||
"gunners" : INDEX_OF_ROLE["gunner"],
|
||||
"werecrows" : INDEX_OF_ROLE["werecrow"],
|
||||
"angels" : INDEX_OF_ROLE["guardian angel"]}
|
||||
"angels" : INDEX_OF_ROLE["guardian angel"],
|
||||
"detectives" : INDEX_OF_ROLE["detective"]}
|
||||
|
||||
|
||||
|
||||
|
@ -39,7 +39,11 @@ def main():
|
||||
nickname=botconfig.NICK,
|
||||
connect_cb=wolfgame.connect_callback
|
||||
)
|
||||
cli.mainLoop()
|
||||
try:
|
||||
cli.mainLoop()
|
||||
except Exception as e:
|
||||
cli.msg(botconfig.CHANNEL, "An error has occured: "+str(e))
|
||||
raise e
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
58
wolfgame.py
58
wolfgame.py
@ -183,7 +183,7 @@ def take_op(cli, nick, chan, rest):
|
||||
@cmd("!sudo revoke", owner_only=True)
|
||||
def revoke(cli, nick, chan, rest):
|
||||
r = rest.strip()
|
||||
if r in botconfig.ADMINS:
|
||||
if var.CLOAKS[var.USERS.index(r)] in botconfig.ADMINS:
|
||||
ladmins = list(botconfig.ADMINS)
|
||||
ladmins.remove(r)
|
||||
botconfig.ADMINS = tuple(ladmins)
|
||||
@ -729,6 +729,9 @@ def on_nick(cli, prefix, nick):
|
||||
if prefix in var.WOUNDED:
|
||||
var.WOUNDED.remove(prefix)
|
||||
var.WOUNDED.append(nick)
|
||||
if prefix in var.INVESTIGATED:
|
||||
var.INVESTIGATED.remove(prefix)
|
||||
var.INVESTIGATED.append(prefix)
|
||||
if prefix in var.VOTES:
|
||||
var.VOTES[nick] = var.VOTES.pop(prefix)
|
||||
for v in var.VOTES.values():
|
||||
@ -816,6 +819,7 @@ def transition_day(cli, gameid=0):
|
||||
|
||||
# Reset daytime variables
|
||||
var.VOTES = {}
|
||||
var.INVESTIGATED = []
|
||||
var.WOUNDED = []
|
||||
var.DAY_START_TIME = datetime.now()
|
||||
|
||||
@ -1173,6 +1177,45 @@ def observe(cli, nick, rest):
|
||||
|
||||
|
||||
|
||||
@pmcmd("id", "!id")
|
||||
def investigate(cli, nick, rest):
|
||||
if var.PHASE in ("none", "join"):
|
||||
cli.notice(nick, "No game is currently running.")
|
||||
return
|
||||
elif nick not in var.list_players():
|
||||
cli.notice(nick, "You're not currently playing.")
|
||||
return
|
||||
if not var.is_role(nick, "detective"):
|
||||
cli.msg(nick, "Only a detective may use this command.")
|
||||
return
|
||||
if var.PHASE != "day":
|
||||
cli.msg(nick, "You may only investigate people during the day.")
|
||||
return
|
||||
if nick in var.INVESTIGATED:
|
||||
cli.msg(nick, "You may only investigate one person per round.")
|
||||
return
|
||||
victim = re.split("\s+", rest)[0].strip().lower()
|
||||
if not victim:
|
||||
cli.msg(nick, "Not enough parameters")
|
||||
return
|
||||
pl = var.list_players()
|
||||
pll = [x.lower() for x in pl]
|
||||
if victim not in pll:
|
||||
cli.msg(nick, "\u0002{0}\u0002 is currently not playing.".format(victim))
|
||||
return
|
||||
victim = pl[pll.index(victim)]
|
||||
|
||||
var.INVESTIGATED.append(nick)
|
||||
cli.msg(nick, ("The results of your investigation have returned. \u0002{0}\u0002"+
|
||||
" is a... \u0002{1}\u0002").format(victim, var.get_role(victim)))
|
||||
if random.random < 0.4: # a 2/5 chance (should be changeable in settings)
|
||||
# Reveal his role!
|
||||
for badguy in var.ROLES["wolf"] + var.ROLES["werecrow"] + var.ROLES["traitor"]:
|
||||
cli.msg(badguy, ("\0002{0}\0002 accidentally drops a paper. The paper reveals "+
|
||||
"that (s)he is the detective!").format(nick))
|
||||
|
||||
|
||||
|
||||
@pmcmd("visit", "!visit")
|
||||
def hvisit(cli, nick, rest):
|
||||
if var.PHASE in ("none", "join"):
|
||||
@ -1330,7 +1373,7 @@ def relay(cli, nick, rest):
|
||||
return
|
||||
badguys = var.ROLES["wolf"] + var.ROLES["traitor"] + var.ROLES["werecrow"]
|
||||
if len(badguys) > 1:
|
||||
if var.get_role(nick) in ("wolf","traitor","werecrow"):
|
||||
if nick in badguys:
|
||||
badguys.remove(nick) # remove self from list
|
||||
for badguy in badguys:
|
||||
cli.msg(badguy, "{0} says: {1}".format(nick, rest))
|
||||
@ -1425,7 +1468,11 @@ def transition_night(cli):
|
||||
' wolf, there is a 50/50 chance of you dying, if you guard '+
|
||||
'a victim, they will live. Use !guard to guard a player.'));
|
||||
cli.msg(g_angel, "Players: " + ", ".join(pl))
|
||||
|
||||
for dttv in var.ROLES["detective"]:
|
||||
cli.msg(dttv, ("You are a \u0002detective\u0002.\n"+
|
||||
"It is your job to determine all the wolves and traitors. "+
|
||||
"Your job is during the day, and you can see the true "+
|
||||
"identity of all users, even traitors."))
|
||||
for d in var.ROLES["village drunk"]:
|
||||
cli.msg(d, 'You have been drinking too much! You are the \u0002village drunk\u0002.')
|
||||
|
||||
@ -1698,7 +1745,6 @@ def fwait(cli, nick, chan, rest):
|
||||
"{1} seconds.").format(nick, var.EXTRA_WAIT))
|
||||
|
||||
|
||||
@cmd("!reset")
|
||||
@cmd("!reset",admin_only=True)
|
||||
def reset_game(cli, nick, chan, rest):
|
||||
if nick in ("nyuszika7h", "jcao219"):
|
||||
reset(cli)
|
||||
reset(cli)
|
Loading…
Reference in New Issue
Block a user