Run, Forrest, Run!
This commit is contained in:
parent
4d03ed03cf
commit
7b2cc43a50
@ -186,7 +186,7 @@
|
||||
"forever_aclone": "It appears that \u0002{0}\u0002 was cloning you, so you are now stuck as a clone forever. How sad.",
|
||||
"clone_success": "You will now be cloning \u0002{0}\u0002 if they die.",
|
||||
"clone_wolf": "\u0002{0}\u0002 cloned \u0002{1}\u0002 and has now become a wolf!",
|
||||
"no_other_wolves": "There are no other wolves",
|
||||
"no_other_wolves": "There are no other wolves.",
|
||||
"lover_suicide": "Saddened by the loss of their lover, \u0002{0}\u0002, a{1} \u0002{2}\u0002, commits suicide.",
|
||||
"lover_suicide_no_reveal": "Saddened by the loss of their lover, \u0002{0}\u0002 commits suicide.",
|
||||
"assassin_fail_totem": "Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.",
|
||||
@ -203,6 +203,12 @@
|
||||
"mad_scientist_kill_single_no_reveal": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. \u0002{1}\u0002 gets hit by the chemicals and dies.",
|
||||
"mad_scientist_fail": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. Thankfully, nobody seems to have gotten hit.",
|
||||
"hunter_discard": "Your target has died, so you may now pick a new one.",
|
||||
"wild_child_already_picked": "You have already picked your idol for this game.",
|
||||
"wild_child_success": "You have picked {0} to be your idol for this game.",
|
||||
"wild_child_as_wolf": "\u0002{0}\u0002's idol has died, and is now a \u0002wolf\u0002!",
|
||||
"wild_child_random_idol": "Upon waking up, the first person you see is \u0002{0}\u0002, and they become your idol.",
|
||||
"idol_died": "Your idol has died, and you are now a \u0002wolf\u0002!",
|
||||
"wild_child_idol": "Your idol is \u0002{0}\u0002.",
|
||||
"idle_death": "\u0002{0}\u0002 didn't get out of bed for a very long time and has been found dead. The survivors bury the \u0002{1}\u0002's body.",
|
||||
"idle_death_no_reveal": "\u0002{0}\u0002 didn't get out of bed for a very long time and has been found dead.",
|
||||
"channel_idle_warning": "{0}: \u0002You have been idling for a while. Please say something soon or you might be declared dead.\u0002",
|
||||
@ -511,6 +517,8 @@
|
||||
"monster_simple": "You are a \u0002monster\u0002.",
|
||||
"lycan_notify": "You are a \u0002lycan\u0002. You are currently on the side of the villagers, but will turn into a wolf instead of dying if you are targeted by the wolves during the night.",
|
||||
"lycan_simple": "You are a \u0002lycan\u0002.",
|
||||
"child_notify": "You are a \u0002wild child\u0002. You must pick an idol with \"choose <nick>\", and you will become a wolf if your idol dies. You are a villager as long as your idol is alive.",
|
||||
"child_simple": "You are a \u0002wild child\u0002.",
|
||||
"vengeful_ghost_notify": "You are a \u0002vengeful ghost\u0002, sworn to take revenge on the {0} that you believe killed you. You must kill one of them with \"kill <nick>\" tonight. If you do not, one of them will be selected at random.",
|
||||
"vengeful_ghost_simple": "You are a \u0002vengeful ghost\u0002.",
|
||||
"drunken_assassin_notification": "You are an \u0002assassin\u0002. In your drunken stupor you have selected \u0002{0}\u0002 as your target.",
|
||||
|
@ -245,6 +245,7 @@ ROLE_GUIDE = OrderedDict([ # This is order-sensitive - many parts of the code re
|
||||
("turncoat" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("clone" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("lycan" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("wild child" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("vengeful ghost" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("succubus" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
("demoniac" , ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )),
|
||||
@ -269,7 +270,7 @@ WOLFTEAM_ROLES = WOLFCHAT_ROLES | {"minion", "cultist"}
|
||||
# These roles either steal away wins or can otherwise win with any team
|
||||
TRUE_NEUTRAL_ROLES = frozenset({"crazed shaman", "fool", "jester", "monster", "clone", "piper", "turncoat", "succubus", "demoniac", "dullahan"})
|
||||
# These are the roles that will NOT be used for when amnesiac turns, everything else is fair game! (var.DEFAULT_ROLE is also added if not in this set)
|
||||
AMNESIAC_BLACKLIST = frozenset({"monster", "demoniac", "minion", "matchmaker", "clone", "doctor", "villager", "cultist", "piper", "dullahan"})
|
||||
AMNESIAC_BLACKLIST = frozenset({"monster", "demoniac", "minion", "matchmaker", "clone", "doctor", "villager", "cultist", "piper", "dullahan", "wild child"})
|
||||
# These roles are seen as wolf by the seer/oracle
|
||||
SEEN_WOLF = WOLF_ROLES | {"monster", "mad scientist", "succubus"}
|
||||
# These are seen as the default role (or villager) when seen by seer (this overrides SEEN_WOLF)
|
||||
@ -283,10 +284,10 @@ BENEFICIAL_TOTEMS = frozenset({"protection", "revealing", "desperation", "influe
|
||||
# NB: if you want a template to apply to everyone, list it here but make the restrictions an empty set. Templates not listed here are considered full roles instead
|
||||
TEMPLATE_RESTRICTIONS = OrderedDict([
|
||||
("cursed villager" , SEEN_WOLF | {"seer", "oracle", "fool", "jester", "priest"}),
|
||||
("gunner" , WOLFTEAM_ROLES | {"fool", "lycan", "jester", "priest"}),
|
||||
("gunner" , WOLFTEAM_ROLES | {"fool", "lycan", "jester", "priest", "wild child"}),
|
||||
("sharpshooter" , frozenset()), # the above gets automatically added to the set. this set is the list of roles that can be gunner but not sharpshooter
|
||||
("mayor" , frozenset({"fool", "jester", "monster"})),
|
||||
("assassin" , WOLF_ROLES | {"traitor", "seer", "augur", "oracle", "harlot", "detective", "bodyguard", "guardian angel", "lycan", "priest"}),
|
||||
("assassin" , WOLF_ROLES | {"traitor", "seer", "augur", "oracle", "harlot", "detective", "bodyguard", "guardian angel", "lycan", "priest", "wild child"}),
|
||||
("bureaucrat" , frozenset()),
|
||||
("blessed villager" , frozenset(ROLE_GUIDE.keys()) - {"villager", "blessed villager", "mayor", "bureaucrat"}),
|
||||
])
|
||||
@ -403,7 +404,8 @@ def plural(role, count=2):
|
||||
bits[-1] = {"person": "people",
|
||||
"wolf": "wolves",
|
||||
"has": "have",
|
||||
"succubus": "succubi"}.get(bits[-1], bits[-1] + "s")
|
||||
"succubus": "succubi",
|
||||
"child": "children"}.get(bits[-1], bits[-1] + "s")
|
||||
return " ".join(bits)
|
||||
|
||||
def list_players(roles = None):
|
||||
@ -440,6 +442,8 @@ def get_reveal_role(nick):
|
||||
role = "amnesiac"
|
||||
elif HIDDEN_CLONE and nick in ORIGINAL_ROLES["clone"]:
|
||||
role = "clone"
|
||||
elif nick in WILD_CHILDREN:
|
||||
role = "wild child"
|
||||
else:
|
||||
role = get_role(nick)
|
||||
|
||||
|
@ -416,6 +416,7 @@ def reset():
|
||||
var.START_VOTES = set() # list of players who have voted to !start
|
||||
var.LOVERS = {} # need to be here for purposes of random
|
||||
var.ENTRANCED = set()
|
||||
var.WILD_CHILDREN = set()
|
||||
|
||||
reset_settings()
|
||||
|
||||
@ -2917,6 +2918,31 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
||||
if nickrole == "clone" and nick in var.CLONED:
|
||||
del var.CLONED[nick]
|
||||
|
||||
for child in var.ROLES["wild child"].copy():
|
||||
if child in var.IDOLS and child not in deadlist:
|
||||
if var.IDOLS[child] in deadlist:
|
||||
pm(cli, child, messages["idol_died"])
|
||||
var.WILD_CHILDREN.add(child)
|
||||
var.ROLES["wild child"].remove(child)
|
||||
var.ROLES["wolf"].add(child)
|
||||
var.FINAL_ROLES[child] = "wolf"
|
||||
wolves = var.list_players(var.WOLFCHAT_ROLES)
|
||||
wolves.remove(child)
|
||||
mass_privmsg(cli, wolves, messages["wild_child_as_wolf"].format(child))
|
||||
if var.PHASE == "day":
|
||||
random.shuffle(wolves)
|
||||
for i, wolf in enumerate(wolves):
|
||||
wolfroles = var.get_role(wolf)
|
||||
cursed = ""
|
||||
if wolf in var.ROLES["cursed villager"]:
|
||||
cursed = "cursed "
|
||||
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, cursed, wolfroles)
|
||||
|
||||
if wolves:
|
||||
pm(cli, child, "Wolves: " + ", ".join(wolves))
|
||||
else:
|
||||
pm(cli, child, messages["no_other_wolves"])
|
||||
|
||||
if death_triggers and var.PHASE in var.GAME_PHASES:
|
||||
if nick in var.LOVERS:
|
||||
others = var.LOVERS[nick].copy()
|
||||
@ -3594,7 +3620,7 @@ def rename_player(cli, prefix, nick):
|
||||
if prefix in dictvar.keys():
|
||||
del dictvar[prefix]
|
||||
for dictvar in (var.VENGEFUL_GHOSTS, var.TOTEMS, var.FINAL_ROLES, var.BITTEN, var.GUNNERS, var.TURNCOATS,
|
||||
var.DOCTORS, var.BITTEN_ROLES, var.LYCAN_ROLES, var.AMNESIAC_ROLES):
|
||||
var.DOCTORS, var.BITTEN_ROLES, var.LYCAN_ROLES, var.AMNESIAC_ROLES, var.IDOLS):
|
||||
if prefix in dictvar.keys():
|
||||
dictvar[nick] = dictvar.pop(prefix)
|
||||
# Looks like {'jacob2': ['5'], '7': ['3']}
|
||||
@ -3640,7 +3666,7 @@ def rename_player(cli, prefix, nick):
|
||||
var.DISEASED, var.TOBEDISEASED, var.RETRIBUTION, var.MISDIRECTED, var.TOBEMISDIRECTED,
|
||||
var.EXCHANGED, var.IMMUNIZED, var.CURED_LYCANS, var.ALPHA_WOLVES, var.CURSED, var.CHARMERS,
|
||||
var.CHARMED, var.TOBECHARMED, var.PRIESTS, var.CONSECRATING, var.ENTRANCED_DYING, var.DYING,
|
||||
var.DECEIVED):
|
||||
var.DECEIVED, var.WILD_CHILDREN):
|
||||
if prefix in setvar:
|
||||
setvar.remove(prefix)
|
||||
setvar.add(nick)
|
||||
@ -4019,6 +4045,15 @@ def transition_day(cli, gameid=0):
|
||||
choose.func(cli, mm, mm, lovers[0] + " " + lovers[1], sendmsg=False)
|
||||
pm(cli, mm, messages["random_matchmaker"])
|
||||
|
||||
for child in var.ROLES["wild child"]:
|
||||
if child not in var.IDOLS:
|
||||
ps = pl[:]
|
||||
pl.remove(child)
|
||||
if ps:
|
||||
target = random.choice(ps)
|
||||
var.IDOLS[child] = target
|
||||
pm(cli, child, messages["wild_child_random_idol"].format(target))
|
||||
|
||||
|
||||
# Reset daytime variables
|
||||
var.INVESTIGATED = set()
|
||||
@ -4752,8 +4787,8 @@ def chk_nightdone(cli):
|
||||
nightroles.append(p)
|
||||
|
||||
if var.FIRST_NIGHT:
|
||||
actedcount += len(var.MATCHMAKERS | var.CLONED.keys())
|
||||
nightroles.extend(get_roles("matchmaker", "clone"))
|
||||
actedcount += len(var.MATCHMAKERS | var.CLONED.keys() | var.IDOLS.keys())
|
||||
nightroles.extend(get_roles("matchmaker", "clone", "wild child"))
|
||||
|
||||
if var.DISEASED_WOLVES:
|
||||
nightroles = [p for p in nightroles if p not in var.list_players(var.WOLF_ROLES - {"wolf cub", "werecrow", "doomsayer"})]
|
||||
@ -5003,6 +5038,7 @@ def check_exchange(cli, actor, nick):
|
||||
elif actor_role in var.WOLF_ROLES - {"werecrow", "wolf cub", "alpha wolf"}:
|
||||
if actor in var.KILLS:
|
||||
del var.KILLS[actor]
|
||||
var.WILD_CHILDREN.discard(actor)
|
||||
elif actor_role == "hunter":
|
||||
if actor in var.OTHER_KILLS:
|
||||
del var.OTHER_KILLS[actor]
|
||||
@ -5024,6 +5060,8 @@ def check_exchange(cli, actor, nick):
|
||||
del var.HVISITED[actor]
|
||||
elif actor_role in ("seer", "oracle", "augur"):
|
||||
var.SEEN.discard(actor)
|
||||
elif actor_role == "wild child": # would that ever happen?
|
||||
var.IDOLS[nick] = var.IDOLS.pop(actor)
|
||||
elif actor_role == "hag":
|
||||
if actor in var.LASTHEXED:
|
||||
if var.LASTHEXED[actor] in var.TOBESILENCED and actor in var.HEXED:
|
||||
@ -5067,6 +5105,7 @@ def check_exchange(cli, actor, nick):
|
||||
elif nick_role in var.WOLF_ROLES - {"werecrow", "wolf cub", "alpha wolf"}:
|
||||
if nick in var.KILLS:
|
||||
del var.KILLS[nick]
|
||||
var.WILD_CHILDREN.discard(nick)
|
||||
elif nick_role == "hunter":
|
||||
if nick in var.OTHER_KILLS:
|
||||
del var.OTHER_KILLS[nick]
|
||||
@ -5088,6 +5127,8 @@ def check_exchange(cli, actor, nick):
|
||||
del var.HVISITED[nick]
|
||||
elif nick_role in ("seer", "oracle", "augur"):
|
||||
var.SEEN.discard(nick)
|
||||
elif nick_role == "wild child":
|
||||
var.IDOLS[actor] = var.IDOLS.pop(nick)
|
||||
elif nick_role == "hag":
|
||||
if nick in var.LASTHEXED:
|
||||
if var.LASTHEXED[nick] in var.TOBESILENCED and nick in var.HEXED:
|
||||
@ -5161,6 +5202,8 @@ def check_exchange(cli, actor, nick):
|
||||
|
||||
if nick_role == "clone":
|
||||
pm(cli, actor, messages["clone_target"].format(nick_target))
|
||||
elif nick_role == "wild child":
|
||||
pm(cli, actor, messages["wild_child_idol"].format(var.IDOLS[actor]))
|
||||
elif nick_role in var.TOTEM_ORDER:
|
||||
if nick_role == "shaman":
|
||||
pm(cli, actor, messages["shaman_totem"].format(nick_totem))
|
||||
@ -5203,6 +5246,8 @@ def check_exchange(cli, actor, nick):
|
||||
|
||||
if actor_role == "clone":
|
||||
pm(cli, nick, messages["clone_target"].format(actor_target))
|
||||
elif actor_role == "wild child":
|
||||
pm(cli, nick, messages["wild_child_idol"].format(var.IDOLS[nick]))
|
||||
elif actor_role in var.TOTEM_ORDER:
|
||||
if actor_role == "shaman":
|
||||
pm(cli, nick, messages["shaman_totem"].format(actor_totem))
|
||||
@ -5917,7 +5962,9 @@ def see(cli, nick, chan, rest):
|
||||
victimrole = var.get_role(victim)
|
||||
vrole = victimrole # keep a copy for logging
|
||||
if role == "seer":
|
||||
if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT) or victim in var.ROLES["cursed villager"]:
|
||||
if victim in var.WILD_CHILDREN:
|
||||
victimrole = "wild child"
|
||||
elif (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT) or victim in var.ROLES["cursed villager"]:
|
||||
victimrole = "wolf"
|
||||
elif victimrole in var.SEEN_DEFAULT:
|
||||
victimrole = var.DEFAULT_ROLE
|
||||
@ -6214,8 +6261,9 @@ def change_sides(cli, nick, chan, rest, sendmsg=True):
|
||||
debuglog("{0} ({1}) SIDE {2}".format(nick, var.get_role(nick), team))
|
||||
chk_nightdone(cli)
|
||||
|
||||
@cmd("choose", "match", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||
def choose(cli, nick, chan, rest, sendmsg=True):
|
||||
@cmd("choose", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||
@cmd("match", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||
def choose_lovers(cli, nick, chan, rest, sendmsg=True):
|
||||
"""Select two players to fall in love. You may select yourself as one of the lovers."""
|
||||
if not var.FIRST_NIGHT:
|
||||
return
|
||||
@ -6484,6 +6532,29 @@ def charm(cli, nick, chan, rest):
|
||||
|
||||
chk_nightdone(cli)
|
||||
|
||||
@cmd("choose", chan=False, pm=True, playing=True, phases=("night",), roles=("wild child",))
|
||||
def choose_idol(cli, nick, chan, rest):
|
||||
"""Pick your idol, if they die, you'll become a wolf!"""
|
||||
if not var.FIRST_NIGHT:
|
||||
return
|
||||
if nick in var.IDOLS:
|
||||
pm(cli, nick, messages["wild_child_already_picked"])
|
||||
return
|
||||
|
||||
victim = get_victim(cli, nick, re.split(" +", rest)[0], False)
|
||||
if not victim:
|
||||
return
|
||||
|
||||
if nick == victim:
|
||||
pm(cli, nick, messages["no_target_self"])
|
||||
return
|
||||
|
||||
var.IDOLS[nick] = victim
|
||||
pm(cli, nick, messages["wild_child_success"].format(victim))
|
||||
|
||||
debuglog("{0} ({1}) IDOLIZE: {2} ({3})".format(nick, var.get_role(nick), victim, var.get_role(victim)))
|
||||
chk_nightdone(cli)
|
||||
|
||||
@hook("featurelist") # For multiple targets with PRIVMSG
|
||||
def getfeatures(cli, nick, *rest):
|
||||
for r in rest:
|
||||
@ -7152,10 +7223,16 @@ def transition_night(cli):
|
||||
|
||||
for lycan in var.ROLES["lycan"]:
|
||||
if lycan in var.PLAYERS and not is_user_simple(lycan):
|
||||
pm(cli, lycan, (messages["lycan_notify"]))
|
||||
pm(cli, lycan, messages["lycan_notify"])
|
||||
else:
|
||||
pm(cli, lycan, messages["lycan_simple"])
|
||||
|
||||
for child in var.ROLES["wild child"]:
|
||||
if child in var.PLAYERS and not is_user_simple(child):
|
||||
pm(cli, child, messages["child_notify"])
|
||||
else:
|
||||
pm(cli, child, messages["child_simple"])
|
||||
|
||||
for v_ghost, who in var.VENGEFUL_GHOSTS.items():
|
||||
if who[0] == "!":
|
||||
continue
|
||||
@ -7579,6 +7656,7 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
||||
var.SICK = set()
|
||||
var.DULLAHAN_TARGETS = {}
|
||||
var.DECEIVED = set()
|
||||
var.IDOLS = {}
|
||||
|
||||
var.DEADCHAT_PLAYERS = set()
|
||||
var.SPECTATING_WOLFCHAT = set()
|
||||
@ -9121,6 +9199,11 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
special_case.append("need to kill {0}".format(", ".join(var.DULLAHAN_TARGETS[nickname] - var.DEAD)))
|
||||
else:
|
||||
special_case.append("All targets dead")
|
||||
elif role == "wild child":
|
||||
if nickname in var.IDOLS:
|
||||
special_case.append("picked {0} as idol".format(var.IDOLS[nickname]))
|
||||
else:
|
||||
special_case.append("no idol picked yet")
|
||||
if nickname not in var.ORIGINAL_ROLES[role] and role not in var.TEMPLATE_RESTRICTIONS:
|
||||
for old_role in var.role_order(): # order doesn't matter here, but oh well
|
||||
if nickname in var.ORIGINAL_ROLES[old_role] and nickname not in var.ROLES[old_role]:
|
||||
|
Loading…
x
Reference in New Issue
Block a user