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 logging
|
||||||
import socket
|
import socket
|
||||||
|
import time
|
||||||
|
|
||||||
from oyoyo.parse import parse_raw_irc_command
|
from oyoyo.parse import parse_raw_irc_command
|
||||||
|
|
||||||
class IRCClientError(Exception):
|
class IRCClientError(Exception):
|
||||||
pass
|
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 add_commands(d):
|
||||||
def dec(cls):
|
def dec(cls):
|
||||||
for c in d:
|
for c in d:
|
||||||
@ -70,6 +107,7 @@ class IRCClient(object):
|
|||||||
self.port = None
|
self.port = None
|
||||||
self.connect_cb = None
|
self.connect_cb = None
|
||||||
self.blocking = True
|
self.blocking = True
|
||||||
|
self.tokenbucket = TokenBucket(3, 7.3)
|
||||||
|
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
self.command_handler = cmd_handler
|
self.command_handler = cmd_handler
|
||||||
@ -181,6 +219,8 @@ class IRCClient(object):
|
|||||||
self.socket.close()
|
self.socket.close()
|
||||||
def msg(self, user, msg):
|
def msg(self, user, msg):
|
||||||
for line in msg.split('\n'):
|
for line in msg.split('\n'):
|
||||||
|
while not self.tokenbucket.consume(1):
|
||||||
|
time.sleep(1)
|
||||||
self.send("PRIVMSG", user, ":{0}".format(line))
|
self.send("PRIVMSG", user, ":{0}".format(line))
|
||||||
privmsg = msg # Same thing
|
privmsg = msg # Same thing
|
||||||
def notice(self, user, msg):
|
def notice(self, user, msg):
|
||||||
|
31
var.py
31
var.py
@ -18,18 +18,19 @@ MANSLAUGHTER_CHANCE = 1/5
|
|||||||
|
|
||||||
GAME_MODES = {}
|
GAME_MODES = {}
|
||||||
|
|
||||||
######################################################################################################
|
#################################################################################################################
|
||||||
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL ##
|
# 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), ##
|
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
||||||
6 : ( 1 , 1 , 1 , 1 , 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), ##
|
8 : ( 1 , 2 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ), ##
|
||||||
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0), ##
|
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ), ##
|
||||||
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1), ##
|
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 ), ##
|
||||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0)} ##
|
15 : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
|
||||||
######################################################################################################
|
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
|
||||||
# Notes: ##
|
#################################################################################################################
|
||||||
######################################################################################################
|
# Notes: ##
|
||||||
|
#################################################################################################################
|
||||||
|
|
||||||
|
|
||||||
ROLE_INDICES = {0 : "seer",
|
ROLE_INDICES = {0 : "seer",
|
||||||
@ -40,7 +41,8 @@ ROLE_INDICES = {0 : "seer",
|
|||||||
5 : "traitor",
|
5 : "traitor",
|
||||||
6 : "gunner",
|
6 : "gunner",
|
||||||
7 : "werecrow",
|
7 : "werecrow",
|
||||||
8 : "guardian angel"}
|
8 : "guardian angel",
|
||||||
|
9 : "detective"}
|
||||||
INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
|
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"],
|
"traitors" : INDEX_OF_ROLE["traitor"],
|
||||||
"gunners" : INDEX_OF_ROLE["gunner"],
|
"gunners" : INDEX_OF_ROLE["gunner"],
|
||||||
"werecrows" : INDEX_OF_ROLE["werecrow"],
|
"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,
|
nickname=botconfig.NICK,
|
||||||
connect_cb=wolfgame.connect_callback
|
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__":
|
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)
|
@cmd("!sudo revoke", owner_only=True)
|
||||||
def revoke(cli, nick, chan, rest):
|
def revoke(cli, nick, chan, rest):
|
||||||
r = rest.strip()
|
r = rest.strip()
|
||||||
if r in botconfig.ADMINS:
|
if var.CLOAKS[var.USERS.index(r)] in botconfig.ADMINS:
|
||||||
ladmins = list(botconfig.ADMINS)
|
ladmins = list(botconfig.ADMINS)
|
||||||
ladmins.remove(r)
|
ladmins.remove(r)
|
||||||
botconfig.ADMINS = tuple(ladmins)
|
botconfig.ADMINS = tuple(ladmins)
|
||||||
@ -729,6 +729,9 @@ def on_nick(cli, prefix, nick):
|
|||||||
if prefix in var.WOUNDED:
|
if prefix in var.WOUNDED:
|
||||||
var.WOUNDED.remove(prefix)
|
var.WOUNDED.remove(prefix)
|
||||||
var.WOUNDED.append(nick)
|
var.WOUNDED.append(nick)
|
||||||
|
if prefix in var.INVESTIGATED:
|
||||||
|
var.INVESTIGATED.remove(prefix)
|
||||||
|
var.INVESTIGATED.append(prefix)
|
||||||
if prefix in var.VOTES:
|
if prefix in var.VOTES:
|
||||||
var.VOTES[nick] = var.VOTES.pop(prefix)
|
var.VOTES[nick] = var.VOTES.pop(prefix)
|
||||||
for v in var.VOTES.values():
|
for v in var.VOTES.values():
|
||||||
@ -816,6 +819,7 @@ def transition_day(cli, gameid=0):
|
|||||||
|
|
||||||
# Reset daytime variables
|
# Reset daytime variables
|
||||||
var.VOTES = {}
|
var.VOTES = {}
|
||||||
|
var.INVESTIGATED = []
|
||||||
var.WOUNDED = []
|
var.WOUNDED = []
|
||||||
var.DAY_START_TIME = datetime.now()
|
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")
|
@pmcmd("visit", "!visit")
|
||||||
def hvisit(cli, nick, rest):
|
def hvisit(cli, nick, rest):
|
||||||
if var.PHASE in ("none", "join"):
|
if var.PHASE in ("none", "join"):
|
||||||
@ -1330,7 +1373,7 @@ def relay(cli, nick, rest):
|
|||||||
return
|
return
|
||||||
badguys = var.ROLES["wolf"] + var.ROLES["traitor"] + var.ROLES["werecrow"]
|
badguys = var.ROLES["wolf"] + var.ROLES["traitor"] + var.ROLES["werecrow"]
|
||||||
if len(badguys) > 1:
|
if len(badguys) > 1:
|
||||||
if var.get_role(nick) in ("wolf","traitor","werecrow"):
|
if nick in badguys:
|
||||||
badguys.remove(nick) # remove self from list
|
badguys.remove(nick) # remove self from list
|
||||||
for badguy in badguys:
|
for badguy in badguys:
|
||||||
cli.msg(badguy, "{0} says: {1}".format(nick, rest))
|
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 '+
|
' wolf, there is a 50/50 chance of you dying, if you guard '+
|
||||||
'a victim, they will live. Use !guard to guard a player.'));
|
'a victim, they will live. Use !guard to guard a player.'));
|
||||||
cli.msg(g_angel, "Players: " + ", ".join(pl))
|
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"]:
|
for d in var.ROLES["village drunk"]:
|
||||||
cli.msg(d, 'You have been drinking too much! You are the \u0002village drunk\u0002.')
|
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))
|
"{1} seconds.").format(nick, var.EXTRA_WAIT))
|
||||||
|
|
||||||
|
|
||||||
@cmd("!reset")
|
@cmd("!reset",admin_only=True)
|
||||||
def reset_game(cli, nick, chan, rest):
|
def reset_game(cli, nick, chan, rest):
|
||||||
if nick in ("nyuszika7h", "jcao219"):
|
reset(cli)
|
||||||
reset(cli)
|
|
Loading…
Reference in New Issue
Block a user