Initial commit to add a bunch of new roles
This commit is contained in:
parent
6717f61e6f
commit
23b2e755ca
@ -525,7 +525,8 @@ def fleave(cli, nick, chann_, rest):
|
|||||||
return
|
return
|
||||||
cli.msg(chan, ("\u0002{0}\u0002 is forcing"+
|
cli.msg(chan, ("\u0002{0}\u0002 is forcing"+
|
||||||
" \u0002{1}\u0002 to leave.").format(nick, a))
|
" \u0002{1}\u0002 to leave.").format(nick, a))
|
||||||
cli.msg(chan, "Say goodbye to the \02{0}\02.".format(var.get_role(a)))
|
if var.ROLE_REVEAL:
|
||||||
|
cli.msg(chan, "Say goodbye to the \02{0}\02.".format(var.get_role(a)))
|
||||||
if var.PHASE == "join":
|
if var.PHASE == "join":
|
||||||
cli.msg(chan, ("New player count: \u0002{0}\u0002").format(len(var.list_players()) - 1))
|
cli.msg(chan, ("New player count: \u0002{0}\u0002").format(len(var.list_players()) - 1))
|
||||||
if var.PHASE in ("day", "night"):
|
if var.PHASE in ("day", "night"):
|
||||||
@ -591,7 +592,7 @@ def stats(cli, nick, chan, rest):
|
|||||||
else:
|
else:
|
||||||
cli.notice(nick, msg)
|
cli.notice(nick, msg)
|
||||||
|
|
||||||
if var.PHASE == "join":
|
if var.PHASE == "join" or not var.ROLE_REVEAL:
|
||||||
return
|
return
|
||||||
|
|
||||||
message = []
|
message = []
|
||||||
@ -609,9 +610,9 @@ def stats(cli, nick, chan, rest):
|
|||||||
if "seer" in rs:
|
if "seer" in rs:
|
||||||
rs.remove("seer")
|
rs.remove("seer")
|
||||||
rs.insert(1, "seer")
|
rs.insert(1, "seer")
|
||||||
if "villager" in rs:
|
if var.DEFAULT_ROLE in rs:
|
||||||
rs.remove("villager")
|
rs.remove(var.DEFAULT_ROLE)
|
||||||
rs.append("villager")
|
rs.append(var.DEFAULT_ROLE)
|
||||||
|
|
||||||
|
|
||||||
firstcount = len(var.ROLES[rs[0]])
|
firstcount = len(var.ROLES[rs[0]])
|
||||||
@ -826,15 +827,12 @@ def stop_game(cli, winner = ""):
|
|||||||
|
|
||||||
roles_msg = []
|
roles_msg = []
|
||||||
|
|
||||||
var.ORIGINAL_ROLES["cursed villager"] = var.CURSED # A hack
|
|
||||||
var.ORIGINAL_ROLES["gunner"] = list(var.GUNNERS.keys())
|
|
||||||
|
|
||||||
lroles = list(var.ORIGINAL_ROLES.keys())
|
lroles = list(var.ORIGINAL_ROLES.keys())
|
||||||
lroles.remove("wolf")
|
lroles.remove("wolf")
|
||||||
lroles.insert(0, "wolf") # picky, howl consistency
|
lroles.insert(0, "wolf") # picky, howl consistency
|
||||||
|
|
||||||
for role in lroles:
|
for role in lroles:
|
||||||
if len(var.ORIGINAL_ROLES[role]) == 0 or role == "villager":
|
if len(var.ORIGINAL_ROLES[role]) == 0 or role == var.DEFAULT_ROLE:
|
||||||
continue
|
continue
|
||||||
playersinrole = list(var.ORIGINAL_ROLES[role])
|
playersinrole = list(var.ORIGINAL_ROLES[role])
|
||||||
for i,plr in enumerate(playersinrole):
|
for i,plr in enumerate(playersinrole):
|
||||||
@ -2402,16 +2400,11 @@ def cgamemode(cli, *args):
|
|||||||
for arg in args:
|
for arg in args:
|
||||||
modeargs = arg.split("=", 1)
|
modeargs = arg.split("=", 1)
|
||||||
|
|
||||||
if len(modeargs) < 2: # no equal sign in the middle of the arg
|
modeargs = map(strip, modeargs)
|
||||||
cli.msg(botconfig.CHANNEL, "Invalid syntax.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
modeargs[0] = modeargs[0].strip()
|
|
||||||
if modeargs[0] in var.GAME_MODES.keys():
|
if modeargs[0] in var.GAME_MODES.keys():
|
||||||
md = modeargs.pop(0)
|
md = modeargs.pop(0)
|
||||||
modeargs[0] = modeargs[0].strip()
|
|
||||||
try:
|
try:
|
||||||
gm = var.GAME_MODES[md](modeargs[0])
|
gm = var.GAME_MODES[md](*modeargs)
|
||||||
for attr in dir(gm):
|
for attr in dir(gm):
|
||||||
val = getattr(gm, attr)
|
val = getattr(gm, attr)
|
||||||
if (hasattr(var, attr) and not callable(val)
|
if (hasattr(var, attr) and not callable(val)
|
||||||
@ -2456,9 +2449,9 @@ def start(cli, nick, chann_, rest):
|
|||||||
cli.msg(chan, "{0}: \u0002{1}\u0002 or more players are required to play.".format(nick, var.MIN_PLAYERS))
|
cli.msg(chan, "{0}: \u0002{1}\u0002 or more players are required to play.".format(nick, var.MIN_PLAYERS))
|
||||||
return
|
return
|
||||||
|
|
||||||
for pcount in range(len(villagers), var.MIN_PLAYERS - 1, -1):
|
for index in range(len(var.ROLES_INDEX), -1, -1):
|
||||||
addroles = var.ROLES_GUIDE.get(pcount)
|
if var.ROLES_INDEX[index] < len(villagers):
|
||||||
if addroles:
|
addroles = {k:v[index] for k,v in var.ROLES_GUIDE}
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
cli.msg(chan, "{0}: No game settings are defined for \u0002{1}\u0002 player games.".format(nick, len(villagers)))
|
cli.msg(chan, "{0}: No game settings are defined for \u0002{1}\u0002 player games.".format(nick, len(villagers)))
|
||||||
@ -2471,10 +2464,8 @@ def start(cli, nick, chann_, rest):
|
|||||||
|
|
||||||
if var.ORIGINAL_SETTINGS: # Custom settings
|
if var.ORIGINAL_SETTINGS: # Custom settings
|
||||||
while True:
|
while True:
|
||||||
wvs = (addroles[var.INDEX_OF_ROLE["wolf"]] +
|
wvs = sum(addroles[r] for r in var.WOLFCHAT_ROLES)
|
||||||
addroles[var.INDEX_OF_ROLE["traitor"]])
|
if len(villagers) < (sum(addroles.values()) - sum([addroles[r] for r in var.TEMPLATE_RESTRICTIONS.keys()])):
|
||||||
if len(villagers) < (sum(addroles) - addroles[var.INDEX_OF_ROLE["gunner"]] -
|
|
||||||
addroles[var.INDEX_OF_ROLE["cursed villager"]]):
|
|
||||||
cli.msg(chan, "There are too few players in the "+
|
cli.msg(chan, "There are too few players in the "+
|
||||||
"game to use the custom roles.")
|
"game to use the custom roles.")
|
||||||
elif not wvs:
|
elif not wvs:
|
||||||
@ -2496,7 +2487,6 @@ def start(cli, nick, chann_, rest):
|
|||||||
COMMANDS["start"] = [lambda *spam: cli.msg(chan, "This command has been disabled by an admin.")]
|
COMMANDS["start"] = [lambda *spam: cli.msg(chan, "This command has been disabled by an admin.")]
|
||||||
|
|
||||||
var.ROLES = {}
|
var.ROLES = {}
|
||||||
var.CURSED = []
|
|
||||||
var.GUNNERS = {}
|
var.GUNNERS = {}
|
||||||
var.WOLF_GUNNERS = {}
|
var.WOLF_GUNNERS = {}
|
||||||
var.SEEN = []
|
var.SEEN = []
|
||||||
@ -2505,10 +2495,8 @@ def start(cli, nick, chann_, rest):
|
|||||||
var.GUARDED = {}
|
var.GUARDED = {}
|
||||||
var.HVISITED = {}
|
var.HVISITED = {}
|
||||||
|
|
||||||
villager_roles = ("gunner", "cursed villager")
|
for role, count in addroles.items():
|
||||||
for i, count in enumerate(addroles):
|
if role in var.TEMPLATE_RESTRICTIONS.keys():
|
||||||
role = var.ROLE_INDICES[i]
|
|
||||||
if role in villager_roles:
|
|
||||||
var.ROLES[role] = [None] * count
|
var.ROLES[role] = [None] * count
|
||||||
continue # We deal with those later, see below
|
continue # We deal with those later, see below
|
||||||
selected = random.sample(villagers, count)
|
selected = random.sample(villagers, count)
|
||||||
@ -2516,43 +2504,32 @@ def start(cli, nick, chann_, rest):
|
|||||||
for x in selected:
|
for x in selected:
|
||||||
villagers.remove(x)
|
villagers.remove(x)
|
||||||
|
|
||||||
# Now for the villager roles
|
# Now for the templates
|
||||||
# Select cursed (just a villager)
|
for template, restrictions in var.TEMPLATE_RESTRICTIONS.items():
|
||||||
if var.ROLES["cursed villager"]:
|
if template == "sharpshooter":
|
||||||
possiblecursed = pl[:]
|
continue # sharpshooter gets applied specially
|
||||||
for cannotbe in (var.ROLES["wolf"] + var.ROLES["werecrow"] +
|
|
||||||
var.ROLES["seer"]):
|
|
||||||
# traitor can be cursed
|
|
||||||
possiblecursed.remove(cannotbe)
|
|
||||||
|
|
||||||
var.CURSED = random.sample(possiblecursed, len(var.ROLES["cursed villager"]))
|
|
||||||
del var.ROLES["cursed villager"]
|
|
||||||
|
|
||||||
# Select gunner (also a villager)
|
|
||||||
if var.ROLES["gunner"]:
|
|
||||||
|
|
||||||
possible = pl[:]
|
possible = pl[:]
|
||||||
for cannotbe in (var.ROLES["wolf"] + var.ROLES["werecrow"] +
|
for cannotbe in [p for r in restrictions for p in var.ROLES[r]]:
|
||||||
var.ROLES["traitor"]):
|
possible.removed(cannotbe)
|
||||||
possible.remove(cannotbe)
|
var.ROLES[template] = random.sample(possible, len(var.ROLES[template]))
|
||||||
|
|
||||||
for csd in var.CURSED: # cursed cannot be gunner
|
# Handle gunner
|
||||||
if csd in possible:
|
cannot_be_sharpshooter = [p for r in var.TEMPLATE_RESTRICTIONS["sharpshooter"] for p in var.ROLES[r]]
|
||||||
possible.remove(csd)
|
for gunner in var.GUNNER_LIST:
|
||||||
|
if gunner in var.ROLES["village drunk"]:
|
||||||
for gnr in random.sample(possible, len(var.ROLES["gunner"])):
|
var.GUNNERS[gunner] = (var.DRUNK_SHOTS_MULTIPLIER * math.ceil(var.SHOTS_MULTIPLIER * len(pl)))
|
||||||
if gnr in var.ROLES["village drunk"]:
|
elif gunner not in cannot_be_sharpshooter and random.random() <= var.SHARPSHOOTER_CHANCE:
|
||||||
var.GUNNERS[gnr] = (var.DRUNK_SHOTS_MULTIPLIER *
|
var.GUNNERS[gunner] = math.ceil(var.SHARPSHOOTER_MULTIPLIER * len(pl))
|
||||||
math.ceil(var.SHOTS_MULTIPLIER * len(pl)))
|
var.ROLES["gunner"].remove(gunner)
|
||||||
else:
|
var.ROLES["sharpshooter"].append(gunner)
|
||||||
var.GUNNERS[gnr] = math.ceil(var.SHOTS_MULTIPLIER * len(pl))
|
else:
|
||||||
del var.ROLES["gunner"]
|
var.GUNNERS[gunner] = math.ceil(var.SHOTS_MULTIPLIER * len(pl))
|
||||||
|
|
||||||
var.SPECIAL_ROLES["goat herder"] = []
|
var.SPECIAL_ROLES["goat herder"] = []
|
||||||
if var.GOAT_HERDER:
|
if var.GOAT_HERDER:
|
||||||
var.SPECIAL_ROLES["goat herder"] = [ nick ]
|
var.SPECIAL_ROLES["goat herder"] = [ nick ]
|
||||||
|
|
||||||
var.ROLES["villager"] = villagers
|
var.ROLES[var.DEFAULT_ROLE] = villagers
|
||||||
|
|
||||||
cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+
|
cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+
|
||||||
"game (a theme of Mafia).").format(", ".join(pl)))
|
"game (a theme of Mafia).").format(", ".join(pl)))
|
||||||
@ -2586,15 +2563,8 @@ def start(cli, nick, chann_, rest):
|
|||||||
for plr in var.ROLES[rol]:
|
for plr in var.ROLES[rol]:
|
||||||
var.LOGGER.logBare(plr, "ROLE", rol)
|
var.LOGGER.logBare(plr, "ROLE", rol)
|
||||||
|
|
||||||
if var.CURSED:
|
|
||||||
var.LOGGER.log("Cursed Villagers: "+", ".join(var.CURSED))
|
|
||||||
|
|
||||||
for plr in var.CURSED:
|
|
||||||
var.LOGGER.logBare(plr+" ROLE cursed villager")
|
|
||||||
if var.GUNNERS:
|
if var.GUNNERS:
|
||||||
var.LOGGER.log("Villagers With Bullets: "+", ".join([x+"("+str(y)+")" for x,y in var.GUNNERS.items()]))
|
var.LOGGER.log("Villagers With Bullets: "+", ".join([x+"("+str(y)+")" for x,y in var.GUNNERS.items()]))
|
||||||
for plr in var.GUNNERS:
|
|
||||||
var.LOGGER.logBare(plr, "ROLE gunner")
|
|
||||||
|
|
||||||
var.LOGGER.log("***")
|
var.LOGGER.log("***")
|
||||||
|
|
||||||
@ -3033,10 +3003,13 @@ def myrole(cli, nick, chan, rest):
|
|||||||
|
|
||||||
# Check for gun/bullets
|
# Check for gun/bullets
|
||||||
if nick in var.GUNNERS and var.GUNNERS[nick]:
|
if nick in var.GUNNERS and var.GUNNERS[nick]:
|
||||||
|
role = "gunner"
|
||||||
|
if nick in var.ROLES["sharpshooter"]:
|
||||||
|
role = "sharpshooter"
|
||||||
if var.GUNNERS[nick] == 1:
|
if var.GUNNERS[nick] == 1:
|
||||||
pm(cli, nick, "You have a \02gun\02 with {0} {1}.".format(var.GUNNERS[nick], "bullet"))
|
pm(cli, nick, "You are a {0} and have a \02gun\02 with {1} {2}.".format(role, var.GUNNERS[nick], "bullet"))
|
||||||
else:
|
else:
|
||||||
pm(cli, nick, "You have a \02gun\02 with {0} {1}.".format(var.GUNNERS[nick], "bullets"))
|
pm(cli, nick, "You are a {0} and have a \02gun\02 with {1} {2}.".format(role, var.GUNNERS[nick], "bullets"))
|
||||||
elif nick in var.WOLF_GUNNERS and var.WOLF_GUNNERS[nick]:
|
elif nick in var.WOLF_GUNNERS and var.WOLF_GUNNERS[nick]:
|
||||||
if var.WOLF_GUNNERS[nick] == 1:
|
if var.WOLF_GUNNERS[nick] == 1:
|
||||||
pm(cli, nick, "You have a \02gun\02 with {0} {1}.".format(var.WOLF_GUNNERS[nick], "bullet"))
|
pm(cli, nick, "You have a \02gun\02 with {0} {1}.".format(var.WOLF_GUNNERS[nick], "bullet"))
|
||||||
@ -3286,9 +3259,6 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
|||||||
def revroles(cli, nick, chan, rest):
|
def revroles(cli, nick, chan, rest):
|
||||||
if var.PHASE != "none":
|
if var.PHASE != "none":
|
||||||
cli.msg(chan, str(var.ROLES))
|
cli.msg(chan, str(var.ROLES))
|
||||||
if var.PHASE in ('night','day'):
|
|
||||||
cli.msg(chan, "Cursed: "+str(var.CURSED))
|
|
||||||
cli.msg(chan, "Gunners: "+str(list(var.GUNNERS.keys())))
|
|
||||||
|
|
||||||
|
|
||||||
@cmd("fgame", admin_only=True)
|
@cmd("fgame", admin_only=True)
|
||||||
@ -3448,12 +3418,8 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
|||||||
if who == botconfig.NICK or not who:
|
if who == botconfig.NICK or not who:
|
||||||
cli.msg(chan, "No.")
|
cli.msg(chan, "No.")
|
||||||
return
|
return
|
||||||
if rol not in var.ROLES.keys():
|
if rol in var.ROLES.keys() or rol.startswith("gunner") or rol.startswith("sharpshooter"):
|
||||||
pl = var.list_players()
|
if rol.startswith("gunner") or rol.startswith("sharpshooter"):
|
||||||
if var.PHASE not in ("night", "day"):
|
|
||||||
cli.msg(chan, "This is only allowed in game.")
|
|
||||||
return
|
|
||||||
if rol.startswith("gunner"):
|
|
||||||
rolargs = re.split(" +",rol, 1)
|
rolargs = re.split(" +",rol, 1)
|
||||||
if len(rolargs) == 2 and rolargs[1].isdigit():
|
if len(rolargs) == 2 and rolargs[1].isdigit():
|
||||||
if len(rolargs[1]) < 7:
|
if len(rolargs[1]) < 7:
|
||||||
@ -3462,19 +3428,12 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
|||||||
else:
|
else:
|
||||||
var.GUNNERS[who] = 999
|
var.GUNNERS[who] = 999
|
||||||
var.WOLF_GUNNERS[who] = 999
|
var.WOLF_GUNNERS[who] = 999
|
||||||
else:
|
elif rol.startswith("gunner"):
|
||||||
var.GUNNERS[who] = math.ceil(var.SHOTS_MULTIPLIER * len(pl))
|
var.GUNNERS[who] = math.ceil(var.SHOTS_MULTIPLIER * len(pl))
|
||||||
if who not in pl:
|
else:
|
||||||
var.ROLES["villager"].append(who)
|
var.GUNNERS[who] = math.ceil(var.SHARPSHOOTER_MULTIPLIER * len(pl))
|
||||||
elif rol == "cursed villager":
|
else:
|
||||||
if who not in var.CURSED:
|
cli.msg(chan, "Not a valid role.")
|
||||||
var.CURSED.append(who)
|
|
||||||
if who not in pl:
|
|
||||||
var.ROLES["villager"].append(who)
|
|
||||||
else:
|
|
||||||
cli.msg(chan, "Not a valid role.")
|
|
||||||
return
|
|
||||||
cli.msg(chan, "Operation successful.")
|
|
||||||
return
|
return
|
||||||
if who in var.list_players():
|
if who in var.list_players():
|
||||||
var.del_player(who)
|
var.del_player(who)
|
||||||
|
@ -12,6 +12,7 @@ GSTATS_RATE_LIMIT = 15
|
|||||||
PSTATS_RATE_LIMIT = 15
|
PSTATS_RATE_LIMIT = 15
|
||||||
TIME_RATE_LIMIT = 60
|
TIME_RATE_LIMIT = 60
|
||||||
SHOTS_MULTIPLIER = .12 # ceil(shots_multiplier * len_players) = bullets given
|
SHOTS_MULTIPLIER = .12 # ceil(shots_multiplier * len_players) = bullets given
|
||||||
|
SHARPSHOOTER_MULTIPLIER = 0.06
|
||||||
MIN_PLAYERS = 4
|
MIN_PLAYERS = 4
|
||||||
MAX_PLAYERS = 21
|
MAX_PLAYERS = 21
|
||||||
DRUNK_SHOTS_MULTIPLIER = 3
|
DRUNK_SHOTS_MULTIPLIER = 3
|
||||||
@ -24,6 +25,9 @@ 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
|
||||||
|
TIME_LORD_WARN = 60
|
||||||
|
TIME_LORD_CHANGE = 30
|
||||||
KILL_IDLE_TIME = 300
|
KILL_IDLE_TIME = 300
|
||||||
WARN_IDLE_TIME = 180
|
WARN_IDLE_TIME = 180
|
||||||
PART_GRACE_TIME = 30
|
PART_GRACE_TIME = 30
|
||||||
@ -38,6 +42,12 @@ GOAT_HERDER = True
|
|||||||
|
|
||||||
SELF_LYNCH_ALLOWED = True
|
SELF_LYNCH_ALLOWED = True
|
||||||
HIDDEN_TRAITOR = True
|
HIDDEN_TRAITOR = True
|
||||||
|
VENGEFUL_GHOST_KNOWS_ROLES = True
|
||||||
|
WOLF_MAYOR = True
|
||||||
|
BODYGUARD_CAN_GUARD_SELF = True
|
||||||
|
START_WITH_DAY = False
|
||||||
|
WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets
|
||||||
|
ROLE_REVEAL = True
|
||||||
|
|
||||||
CARE_BOLD = False
|
CARE_BOLD = False
|
||||||
CARE_COLOR = False
|
CARE_COLOR = False
|
||||||
@ -47,48 +57,97 @@ KILL_BOLD = False
|
|||||||
LOG_FILENAME = ""
|
LOG_FILENAME = ""
|
||||||
BARE_LOG_FILENAME = ""
|
BARE_LOG_FILENAME = ""
|
||||||
|
|
||||||
# HIT MISS SUICIDE
|
# HIT MISS SUICIDE HEADSHOT
|
||||||
GUN_CHANCES = ( 5/7 , 1/7 , 1/7 )
|
GUN_CHANCES = ( 5/7 , 1/7 , 1/7 , 2/5 )
|
||||||
DRUNK_GUN_CHANCES = ( 2/7 , 3/7 , 2/7 )
|
WOLF_GUN_CHANCES = ( 5/7 , 1/7 , 1/7 , 2/5 )
|
||||||
MANSLAUGHTER_CHANCE = 2/5 # ACCIDENTAL HEADSHOT (FATAL)
|
DRUNK_GUN_CHANCES = ( 2/7 , 3/7 , 2/7 , 2/5 )
|
||||||
|
SHARPSHOOTER_GUN_CHANCES = ( 1 , 0 , 0 , 1 )
|
||||||
|
|
||||||
GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE = 1/4
|
GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE = 1/4
|
||||||
GUARDIAN_ANGEL_DIES_CHANCE = 1/2
|
GUARDIAN_ANGEL_DIES_CHANCE = 0
|
||||||
|
BODYGUARD_DIES_CHANCE = 0
|
||||||
DETECTIVE_REVEALED_CHANCE = 2/5
|
DETECTIVE_REVEALED_CHANCE = 2/5
|
||||||
|
SHARPSHOOTER_CHANCE = 1/5 # if sharpshooter is enabled, chance that a gunner will become a sharpshooter instead
|
||||||
|
|
||||||
#################################################################################################################
|
AMNESIAC_NIGHTS = 3 # amnesiac gets to know their actual role on this night
|
||||||
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
|
BUREAUCRAT_VOTES = 2 # bureaucrat votes count for this many normal votes
|
||||||
#################################################################################################################
|
|
||||||
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
# DEATH PROTECTION REVEALING NARCOLEPSY SILENCE DESPERATION
|
||||||
6 : ( 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
|
TOTEM_CHANCES = ( 1/6 , 1/6 , 1/6 , 1/6 , 1/6 , 1/6 )
|
||||||
8 : ( 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 ), ##
|
|
||||||
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ), ##
|
|
||||||
12 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ), ##
|
|
||||||
15 : ( 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 ), ##
|
|
||||||
17 : ( 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
|
||||||
18 : ( 1 , 3 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
|
||||||
20 : ( 1 , 4 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), ##
|
|
||||||
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
|
|
||||||
#################################################################################################################
|
|
||||||
# Notes: ##
|
|
||||||
#################################################################################################################
|
|
||||||
|
|
||||||
GAME_MODES = {}
|
GAME_MODES = {}
|
||||||
AWAY = ['services.', 'services.int'] # cloaks of people who are away.
|
AWAY = ['services.', 'services.int'] # cloaks of people who are away.
|
||||||
SIMPLE_NOTIFY = [] # cloaks of people who !simple, who want everything /notice'd
|
SIMPLE_NOTIFY = [] # cloaks of people who !simple, who want everything /notice'd
|
||||||
|
|
||||||
ROLE_INDICES = {0 : "seer",
|
# 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")
|
||||||
1 : "wolf",
|
DEFAULT_ROLE = "villager"
|
||||||
2 : "cursed villager",
|
ROLES_INDEX = ( 4 , 6 , 8 , 10 , 12 , 15 , 17 , 18 , 20 )
|
||||||
3 : "village drunk",
|
ROLES_GUIDE = {# village roles
|
||||||
4 : "harlot",
|
"villager" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
5 : "traitor",
|
"seer" : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
|
||||||
6 : "gunner",
|
"oracle" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
7 : "werecrow",
|
"village drunk" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
|
||||||
8 : "guardian angel",
|
"harlot" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ),
|
||||||
9 : "detective"}
|
"guardian angel" : ( 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ),
|
||||||
|
"bodyguard" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
|
"detective" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ),
|
||||||
|
"village elder" : ( 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 ),
|
||||||
|
"mad scientist" : ( 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 ),
|
||||||
|
# wolf roles
|
||||||
|
"wolf" : ( 1 , 1 , 1 , 2 , 2 , 3 , 3 , 3 , 4 ),
|
||||||
|
"traitor" : ( 0 , 0 , 1 , 1 , 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 ),
|
||||||
|
"minion" : ( 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 ),
|
||||||
|
"sorcerer" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
|
# neutral roles
|
||||||
|
"lycan" : ( 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 ),
|
||||||
|
"crazed shaman" : ( 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 ),
|
||||||
|
# templates
|
||||||
|
"cursed villager" : ( 0 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 ),
|
||||||
|
"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.
|
||||||
|
"sharpshooter" : ( 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 ),
|
||||||
|
"amnesiac" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
|
"bureaucrat" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ),
|
||||||
|
}
|
||||||
|
|
||||||
INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
|
# Harlot dies when visiting, gunner kills when shooting, GA and bodyguard have a chance at dying when guarding
|
||||||
|
WOLF_ROLES = ["wolf", "werecrow", "wolf cub"]
|
||||||
|
# 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"]
|
||||||
|
# Wins with the wolves, even if the roles are not necessarily wolves themselves
|
||||||
|
WOLFTEAM_ROLES = ["wolf", "traitor", "werecrow", "hag", "wolf cub", "sorceror", "minion", "cultist"]
|
||||||
|
|
||||||
|
# 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
|
||||||
|
TEMPLATE_RESTRICTIONS = {"cursed villager" : ["wolf", "wolf cub", "werecrow", "seer", "fool"],
|
||||||
|
"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"],
|
||||||
|
"mayor" : ["fool"],
|
||||||
|
"assassin" : ["seer", "harlot", "detective", "bodyguard", "guardian angel", "village drunk", "hunter", "shaman", "crazed shaman", "fool", "mayor"],
|
||||||
|
"amnesiac" : ["villager", "cultist"],
|
||||||
|
"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.",
|
||||||
@ -98,14 +157,17 @@ LYNCH_MESSAGES = ("The villagers, after much debate, finally decide on lynching
|
|||||||
"Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a \u0002{1}\u0002.",
|
"Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a \u0002{1}\u0002.",
|
||||||
"Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a \u0002{1}\u0002.",
|
"Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a \u0002{1}\u0002.",
|
||||||
"Before the rope is pulled, \u0002{0}\u0002, the \u0002{1}\u0002, throws a grenade at the mob. The grenade explodes early.")
|
"Before the rope is pulled, \u0002{0}\u0002, the \u0002{1}\u0002, throws a grenade at the mob. The grenade explodes early.")
|
||||||
|
LYNCH_MESSAGES_NO_REVEAL = ("The villagers, after much debate, finally decide on lynching \u0002{0}\u0002.",
|
||||||
|
"Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002.",
|
||||||
|
"Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged.",
|
||||||
|
"Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows.",
|
||||||
|
"Before the rope is pulled, \u0002{0}\u0002 throws a grenade at the mob. The grenade explodes early.")
|
||||||
|
|
||||||
import botconfig
|
import botconfig
|
||||||
|
|
||||||
RULES = (botconfig.CHANNEL + " channel rules: http://wolf.xnrand.com/rules")
|
RULES = (botconfig.CHANNEL + " channel rules: http://wolf.xnrand.com/rules")
|
||||||
|
|
||||||
# Other settings:
|
# Other settings:
|
||||||
START_WITH_DAY = False
|
|
||||||
WOLF_STEALS_GUN = True # at night, the wolf can steal steal the victim's bullets
|
|
||||||
|
|
||||||
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
OPT_IN_PING = False # instead of !away/!back, users can opt-in to be pinged
|
||||||
PING_IN = [] # cloaks of users who have opted in for ping
|
PING_IN = [] # cloaks of users who have opted in for ping
|
||||||
@ -152,28 +214,13 @@ def game_mode(name):
|
|||||||
return decor
|
return decor
|
||||||
|
|
||||||
|
|
||||||
CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"],
|
# TODO: implement more game modes
|
||||||
"wolves" : INDEX_OF_ROLE["wolf"],
|
|
||||||
"cursed" : INDEX_OF_ROLE["cursed villager"],
|
|
||||||
"drunks" : INDEX_OF_ROLE["village drunk"],
|
|
||||||
"harlots" : INDEX_OF_ROLE["harlot"],
|
|
||||||
"traitors" : INDEX_OF_ROLE["traitor"],
|
|
||||||
"gunners" : INDEX_OF_ROLE["gunner"],
|
|
||||||
"werecrows" : INDEX_OF_ROLE["werecrow"],
|
|
||||||
"angels" : INDEX_OF_ROLE["guardian angel"],
|
|
||||||
"detectives" : INDEX_OF_ROLE["detective"]}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: implement game modes
|
|
||||||
@game_mode("roles")
|
@game_mode("roles")
|
||||||
class ChangedRolesMode(object):
|
class ChangedRolesMode(object):
|
||||||
"""Example: !fgame roles=wolves:1,seers:0,angels: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.ROLES_GUIDE = ROLES_GUIDE.copy()
|
||||||
lx = list(ROLES_GUIDE[None])
|
|
||||||
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.")
|
||||||
@ -184,16 +231,29 @@ class ChangedRolesMode(object):
|
|||||||
role, num = change
|
role, num = change
|
||||||
try:
|
try:
|
||||||
num = int(num)
|
num = int(num)
|
||||||
try:
|
if role.lower() in self.ROLES_GUIDE:
|
||||||
lx[CHANGEABLE_ROLES[role.lower()]] = num
|
self.ROLES_GUIDE[role.lower()] = tuple([num] * len(ROLES_INDEX))
|
||||||
except KeyError:
|
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))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise InvalidModeException("A bad value was used in mode roles.")
|
raise InvalidModeException("A bad value was used in mode roles.")
|
||||||
for k in ROLES_GUIDE.keys():
|
|
||||||
self.ROLES_GUIDE[k] = tuple(lx)
|
|
||||||
|
|
||||||
|
@game_mode("evilvillage")
|
||||||
|
class EvilVillageMode(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.MIN_PLAYERS = 6
|
||||||
|
self.MAX_PLAYERS = 12
|
||||||
|
self.DEFAULT_ROLE = "cultist"
|
||||||
|
self.ROLES_INDEX = ( 6 , 10 )
|
||||||
|
self.ROLES_GUIDE = {# village roles
|
||||||
|
"oracle" : ( 1 , 1 ),
|
||||||
|
"shaman" : ( 1 , 1 ),
|
||||||
|
"bodyguard" : ( 0 , 1 ),
|
||||||
|
# wolf roles
|
||||||
|
"wolf" : ( 1 , 1 ),
|
||||||
|
"minion" : ( 0 , 1 ),
|
||||||
|
}
|
||||||
|
|
||||||
# Persistence
|
# Persistence
|
||||||
|
|
||||||
@ -221,7 +281,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 ["villager"]+list(ROLE_INDICES.values()):
|
for x in list(ROLES_GUIDE.keys()):
|
||||||
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
c.execute("INSERT OR REPLACE INTO roles (role) VALUES (?)", (x,))
|
||||||
|
|
||||||
|
|
||||||
@ -306,7 +366,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 ["villager"] + [v.lower() for k, v in ROLE_INDICES.items()]:
|
if role.lower() not in [k.lower() for k in ROLES_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,))
|
||||||
@ -325,7 +385,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 ["villager"] + [v for k, v in ROLE_INDICES.items()]:
|
for role in [k.lower() for k in ROLES_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:
|
||||||
|
Loading…
Reference in New Issue
Block a user