Roughly halfway done with adding new roles

This commit is contained in:
Skizzerz 2014-07-12 19:40:20 -05:00
parent 3f61a60f21
commit 7011c9b5d0
2 changed files with 749 additions and 316 deletions

File diff suppressed because it is too large Load Diff

View File

@ -25,9 +25,11 @@ JOIN_TIME_LIMIT = 3600
SHORT_DAY_PLAYERS = 6 # Number of players left to have a short day SHORT_DAY_PLAYERS = 6 # Number of players left to have a short day
SHORT_DAY_LIMIT_WARN = 400 SHORT_DAY_LIMIT_WARN = 400
SHORT_DAY_LIMIT_CHANGE = 120 SHORT_DAY_LIMIT_CHANGE = 120
# If time lord is lynched, the day timer gets set to this instead # If time lord is lynched, the timers get set to this instead (90s day, 60s night)
TIME_LORD_WARN = 60 TIME_LORD_DAY_WARN = 60
TIME_LORD_CHANGE = 30 TIME_LORD_DAY_CHANGE = 30
TIME_LORD_NIGHT_LIMIT = 60
TIME_LORD_NIGHT_WARN = 40
KILL_IDLE_TIME = 300 KILL_IDLE_TIME = 300
WARN_IDLE_TIME = 180 WARN_IDLE_TIME = 180
PART_GRACE_TIME = 30 PART_GRACE_TIME = 30
@ -43,7 +45,6 @@ GOAT_HERDER = True
SELF_LYNCH_ALLOWED = True SELF_LYNCH_ALLOWED = True
HIDDEN_TRAITOR = True HIDDEN_TRAITOR = True
VENGEFUL_GHOST_KNOWS_ROLES = True VENGEFUL_GHOST_KNOWS_ROLES = True
WOLF_MAYOR = True
BODYGUARD_CAN_GUARD_SELF = True BODYGUARD_CAN_GUARD_SELF = True
START_WITH_DAY = False START_WITH_DAY = False
WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets
@ -81,55 +82,58 @@ SIMPLE_NOTIFY = [] # cloaks of people who !simple, who want everything /notice'
# TODO: move this to a game mode called "fixed" once we implement a way to randomize roles (and have that game mode be called "random") # TODO: move this to a game mode called "fixed" once we implement a way to randomize roles (and have that game mode be called "random")
DEFAULT_ROLE = "villager" DEFAULT_ROLE = "villager"
ROLES_INDEX = ( 4 , 6 , 8 , 10 , 12 , 15 , 17 , 18 , 20 ) ROLE_INDEX = ( 4 , 6 , 8 , 10 , 12 , 15 , 17 , 18 , 20 )
ROLES_GUIDE = {# village roles ROLE_GUIDE = {# village roles
"villager" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "villager" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"seer" : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "seer" : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
"oracle" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "oracle" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"village drunk" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "village drunk" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
"harlot" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "harlot" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
"guardian angel" : ( 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ), "guardian angel" : ( 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ),
"bodyguard" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "bodyguard" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"detective" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ), "detective" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ),
"village elder" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "village elder" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"time lord" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "time lord" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"matchmaker" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "matchmaker" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"mad scientist" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "mad scientist" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"hunter" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "hunter" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"shaman" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "shaman" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
# wolf roles # wolf roles
"wolf" : ( 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3 , 4 ), "wolf" : ( 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3 , 4 ),
"traitor" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "traitor" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
"werecrow" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ), "werecrow" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ),
"cultist" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "cultist" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"minion" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "minion" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"hag" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "hag" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"wolf cub" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "wolf cub" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"sorcerer" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "sorcerer" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
# neutral roles # neutral roles
"lycan" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "lycan" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"vengeful ghost" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "vengeful ghost" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"clone" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "clone" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"crazed shaman" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "crazed shaman" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"fool" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "fool" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"monster" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "monster" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
# templates # templates
"cursed villager" : ( 0 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 ), "cursed villager" : ( 0 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 ),
"gunner" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ), "gunner" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ),
# NB: for sharpshooter, numbers can't be higher than gunner, since gunners get converted to sharpshooters. This is the MAX number of gunners that can be converted. # NB: for sharpshooter, numbers can't be higher than gunner, since gunners get converted to sharpshooters. This is the MAX number of gunners that can be converted.
"sharpshooter" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "sharpshooter" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"mayor" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "mayor" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"assassin" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "assassin" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"amnesiac" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "amnesiac" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
"bureaucrat" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "bureaucrat" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
} }
# Harlot dies when visiting, gunner kills when shooting, GA and bodyguard have a chance at dying when guarding # Harlot dies when visiting, gunner kills when shooting, GA and bodyguard have a chance at dying when guarding
# If every wolf role dies, the game ends and village wins and there are no remaining traitors, the game ends and villagers win
WOLF_ROLES = ["wolf", "werecrow", "wolf cub"] WOLF_ROLES = ["wolf", "werecrow", "wolf cub"]
# Access to wolfchat, and counted towards the # of wolves vs villagers when determining if a side has won # Access to wolfchat, and counted towards the # of wolves vs villagers when determining if a side has won
WOLFCHAT_ROLES = ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorceror"] WOLFCHAT_ROLES = ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorceror"]
# Wins with the wolves, even if the roles are not necessarily wolves themselves # Wins with the wolves, even if the roles are not necessarily wolves themselves
WOLFTEAM_ROLES = ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorceror", "minion", "cultist"] WOLFTEAM_ROLES = ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorceror", "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 = ["vengeful ghost", "crazed shaman", "fool"]
# 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 # 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 # 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
@ -137,17 +141,10 @@ TEMPLATE_RESTRICTIONS = {"cursed villager" : ["wolf", "wolf cub", "werecrow", "s
"gunner" : ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorcerer", "minion", "cultist", "fool", "cursed villager"], "gunner" : ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorcerer", "minion", "cultist", "fool", "cursed villager"],
"sharpshooter" : ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorcerer", "minion", "cultist", "fool", "cursed villager"], "sharpshooter" : ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorcerer", "minion", "cultist", "fool", "cursed villager"],
"mayor" : ["fool"], "mayor" : ["fool"],
"assassin" : ["seer", "harlot", "detective", "bodyguard", "guardian angel", "village drunk", "hunter", "shaman", "crazed shaman", "fool", "mayor"], "assassin" : ["seer", "harlot", "detective", "bodyguard", "guardian angel", "village drunk", "hunter", "shaman", "crazed shaman", "fool", "mayor", "wolf", "werecrow", "wolf cub", "traitor", "lycan"],
"amnesiac" : ["villager", "cultist"], "amnesiac" : ["villager", "cultist", "wolf", "wolf cub", "werecrow"],
"bureaucrat" : [], "bureaucrat" : [],
} }
TEMPLATE_KEYS = {"cursed villager" : "CURSED",
"gunner" : "GUNNER_LIST",
"mayor" : "MAYORS",
"assassin" : "ASSASSINS",
"amnesiac" : "AMNESIACS",
"bureaucrat" : "BUREAUCRATS",
}
NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.", NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.",
"A pool of blood and wolf paw prints are found.", "A pool of blood and wolf paw prints are found.",
@ -188,6 +185,8 @@ def list_players():
def list_players_and_roles(): def list_players_and_roles():
plr = {} plr = {}
for x in ROLES.keys(): for x in ROLES.keys():
if x in TEMPLATE_RESTRICTIONS.keys():
continue # only get actual roles
for p in ROLES[x]: for p in ROLES[x]:
plr[p] = x plr[p] = x
return plr return plr
@ -196,15 +195,23 @@ get_role = lambda plyr: list_players_and_roles()[plyr]
def get_reveal_role(nick): def get_reveal_role(nick):
if HIDDEN_TRAITOR and get_role(nick) == "traitor": if HIDDEN_TRAITOR and get_role(nick) == "traitor":
return "villager" return var.DEFAULT_ROLE
else: else:
return get_role(nick) return get_role(nick)
def del_player(pname): def del_player(pname):
prole = get_role(pname) prole = get_role(pname)
ROLES[prole].remove(pname) ROLES[prole].remove(pname)
tpls = get_templates(nick)
for t in tpls:
ROLES[t].remove(pname)
def get_templates(nick):
tpl = []
for x in TEMPLATE_RESTRICTIONS.keys():
if nick in ROLES[x]:
tpl.append(x)
return tpl
class InvalidModeException(Exception): pass class InvalidModeException(Exception): pass
def game_mode(name): def game_mode(name):
@ -220,7 +227,7 @@ class ChangedRolesMode(object):
"""Example: !fgame roles=wolf:1,seer:0,guardian angel:1""" """Example: !fgame roles=wolf:1,seer:0,guardian angel:1"""
def __init__(self, arg = ""): def __init__(self, arg = ""):
self.ROLES_GUIDE = ROLES_GUIDE.copy() self.ROLE_GUIDE = ROLE_GUIDE.copy()
pairs = arg.split(",") pairs = arg.split(",")
if not pairs: if not pairs:
raise InvalidModeException("Invalid syntax for mode roles.") raise InvalidModeException("Invalid syntax for mode roles.")
@ -231,8 +238,8 @@ class ChangedRolesMode(object):
role, num = change role, num = change
try: try:
num = int(num) num = int(num)
if role.lower() in self.ROLES_GUIDE: if role.lower() in self.ROLE_GUIDE:
self.ROLES_GUIDE[role.lower()] = tuple([num] * len(ROLES_INDEX)) self.ROLE_GUIDE[role.lower()] = tuple([num] * len(ROLE_INDEX))
else: else:
raise InvalidModeException(("The role \u0002{0}\u0002 "+ raise InvalidModeException(("The role \u0002{0}\u0002 "+
"is not valid.").format(role)) "is not valid.").format(role))
@ -245,15 +252,15 @@ class EvilVillageMode(object):
self.MIN_PLAYERS = 6 self.MIN_PLAYERS = 6
self.MAX_PLAYERS = 12 self.MAX_PLAYERS = 12
self.DEFAULT_ROLE = "cultist" self.DEFAULT_ROLE = "cultist"
self.ROLES_INDEX = ( 6 , 10 ) self.ROLE_INDEX = ( 6 , 10 )
self.ROLES_GUIDE = {# village roles self.ROLE_GUIDE = {# village roles
"oracle" : ( 1 , 1 ), "oracle" : ( 1 , 1 ),
"shaman" : ( 1 , 1 ), "shaman" : ( 1 , 1 ),
"bodyguard" : ( 0 , 1 ), "bodyguard" : ( 0 , 1 ),
# wolf roles # wolf roles
"wolf" : ( 1 , 1 ), "wolf" : ( 1 , 1 ),
"minion" : ( 0 , 1 ), "minion" : ( 0 , 1 ),
} }
# Persistence # Persistence
@ -281,7 +288,7 @@ with conn:
c.execute('DROP TABLE IF EXISTS roles') c.execute('DROP TABLE IF EXISTS roles')
c.execute('CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)') c.execute('CREATE TABLE roles (id INTEGER PRIMARY KEY AUTOINCREMENT, role TEXT)')
for x in list(ROLES_GUIDE.keys()): for x in list(ROLE_GUIDE.keys()):
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,)) c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
@ -366,7 +373,7 @@ def update_game_stats(size, winner):
(size, vwins, wwins, total)) (size, vwins, wwins, total))
def get_player_stats(acc, role): def get_player_stats(acc, role):
if role.lower() not in [k.lower() for k in ROLES_GUIDE.keys()]: if role.lower() not in [k.lower() for k in ROLE_GUIDE.keys()]:
return "No such role: {0}".format(role) return "No such role: {0}".format(role)
with conn: with conn:
c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,)) c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,))
@ -385,7 +392,7 @@ def get_player_totals(acc):
c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,)) c.execute("SELECT player FROM rolestats WHERE player=? COLLATE NOCASE", (acc,))
player = c.fetchone() player = c.fetchone()
if player: if player:
for role in [k.lower() for k in ROLES_GUIDE.keys()]: for role in [k.lower() for k in ROLE_GUIDE.keys()]:
c.execute("SELECT totalgames FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE", (acc, role)) c.execute("SELECT totalgames FROM rolestats WHERE player=? COLLATE NOCASE AND role=? COLLATE NOCASE", (acc, role))
row = c.fetchone() row = c.fetchone()
if row: if row: