split VG
This commit is contained in:
parent
fe4ccc3ca7
commit
b5571c82e0
@ -142,7 +142,7 @@ def on_transition_day(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
evt.data["victims"].append(d)
|
||||
evt.data["onlybywolves"].discard(d)
|
||||
evt.data["killers"][d] = k
|
||||
evt.data["killers"][d].append(k)
|
||||
del KILLS[k]
|
||||
|
||||
@event_listener("exchange_roles")
|
||||
|
@ -110,7 +110,7 @@ def on_transition_day(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
evt.data["victims"].append(d)
|
||||
evt.data["onlybywolves"].discard(d)
|
||||
evt.data["killers"][d] = k
|
||||
evt.data["killers"][d].append(k)
|
||||
# important, otherwise our del_player listener lets hunter kill again
|
||||
del KILLS[k]
|
||||
|
||||
|
237
src/roles/vengefulghost.py
Normal file
237
src/roles/vengefulghost.py
Normal file
@ -0,0 +1,237 @@
|
||||
import re
|
||||
import random
|
||||
from collections import defaultdict
|
||||
|
||||
import src.settings as var
|
||||
from src.utilities import *
|
||||
from src import debuglog, errlog, plog
|
||||
from src.decorators import cmd, event_listener
|
||||
from src.messages import messages
|
||||
from src.events import Event
|
||||
|
||||
KILLS = {} # type: Dict[str, str]
|
||||
GHOSTS = {} # type: Dict[str, str]
|
||||
|
||||
@cmd("kill", chan=False, pm=True, playing=False, phases=("night",))
|
||||
def vg_kill(cli, nick, chan, rest):
|
||||
"""Take revenge on someone each night after you die."""
|
||||
if nick not in GHOSTS or GHOSTS[nick][0] == "!":
|
||||
return
|
||||
if nick in var.SILENCED:
|
||||
pm(cli, nick, messages["silenced"])
|
||||
return
|
||||
|
||||
victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
|
||||
if not victim:
|
||||
return
|
||||
|
||||
if victim == nick:
|
||||
pm(cli, nick, messages["player_dead"])
|
||||
return
|
||||
|
||||
wolves = list_players(var.WOLFTEAM_ROLES)
|
||||
if GHOSTS[nick] == "wolves" and victim not in wolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_wolf"])
|
||||
return
|
||||
elif GHOSTS[nick] == "villagers" and victim in wolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_villager"])
|
||||
return
|
||||
|
||||
orig = victim
|
||||
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": False})
|
||||
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
||||
if evt.prevent_default:
|
||||
return
|
||||
victim = evt.data["target"]
|
||||
|
||||
KILLS[nick] = victim
|
||||
|
||||
msg = messages["wolf_target"].format(orig)
|
||||
pm(cli, nick, messages["player"].format(msg))
|
||||
|
||||
debuglog("{0} ({1}) KILL: {2} ({3})".format(nick, get_role(nick), victim, get_role(victim)))
|
||||
chk_nightdone(cli)
|
||||
|
||||
@cmd("retract", "r", chan=False, pm=True, playing=False, phases=("night",))
|
||||
def vg_retract(cli, nick, chan, rest):
|
||||
"""Removes a vengeful ghost's kill selection."""
|
||||
if nick not in GHOSTS:
|
||||
return
|
||||
if nick in KILLS:
|
||||
del KILLS[nick]
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
|
||||
@event_listener("list_participants")
|
||||
def on_list_participants(evt, var):
|
||||
evt.data["pl"].extend([p for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
|
||||
@event_listener("player_win", priority=1)
|
||||
def on_player_win(evt, cli, var, nick, role, winner, survived):
|
||||
# alive VG winning is handled in villager.py
|
||||
# extending VG to work with new teams can be done by registering
|
||||
# a listener at priority > 1, importing src.roles.vengefulghost,
|
||||
# and checking if the nick is in GHOSTS.
|
||||
if nick in GHOSTS:
|
||||
evt.data["special"].append("vg activated")
|
||||
against = GHOSTS[nick]
|
||||
if GHOSTS[nick][0] == "!":
|
||||
evt.data["special"].append("vg driven off")
|
||||
against = against[1:]
|
||||
if against == "villagers" and winner == "wolves":
|
||||
won = True
|
||||
iwon = True
|
||||
elif against == "wolves" and winner == "villagers":
|
||||
won = True
|
||||
iwon = True
|
||||
else:
|
||||
won = False
|
||||
iwon = False
|
||||
|
||||
@event_listener("del_player", priority=6)
|
||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||
for h,v in list(KILLS.items()):
|
||||
if v == nick:
|
||||
pm(cli, h, messages["hunter_discard"])
|
||||
del KILLS[h]
|
||||
# extending VG to work with new teams can be done by registering a listener
|
||||
# at priority < 6, importing src.roles.vengefulghost, and setting
|
||||
# GHOSTS[nick] to something; if that is done then this logic is not run.
|
||||
if death_triggers and nickrole == "vengeful ghost" and nick not in GHOSTS:
|
||||
if evt.params.killer_role in var.WOLFTEAM_ROLES:
|
||||
GHOSTS[nick] = "wolves"
|
||||
else:
|
||||
GHOSTS[nick] = "villagers"
|
||||
pm(cli, nick, messages["vengeful_turn"].format(GHOSTS[nick]))
|
||||
debuglog(nick, "(vengeful ghost) TRIGGER", GHOSTS[nick])
|
||||
|
||||
@event_listener("rename_player")
|
||||
def on_rename(evt, cli, var, prefix, nick):
|
||||
kvp = []
|
||||
for a,b in KILLS.items():
|
||||
if a == prefix:
|
||||
a = nick
|
||||
if b == prefix:
|
||||
b = nick
|
||||
kvp.append((a,b))
|
||||
KILLS.update(kvp)
|
||||
if prefix in KILLS:
|
||||
del KILLS[prefix]
|
||||
if prefix in GHOSTS:
|
||||
GHOSTS[nick] = GHOSTS.pop(prefix)
|
||||
|
||||
@event_listener("night_acted")
|
||||
def on_acted(evt, cli, var, nick, sender):
|
||||
if nick in KILLS:
|
||||
evt.data["acted"] = True
|
||||
|
||||
@event_listener("transition_day_begin", priority=6)
|
||||
def on_transition_day_begin(evt, cli, var):
|
||||
# select a random target for VG if they didn't kill
|
||||
wolves = set(list_players(var.WOLFTEAM_ROLES))
|
||||
villagers = set(list_players()) - wolves
|
||||
for ghost, target in GHOSTS.items():
|
||||
if target[0] == "!" or ghost in var.SILENCED:
|
||||
continue
|
||||
if ghost not in KILLS:
|
||||
choice = set()
|
||||
if target == "wolves":
|
||||
choice = wolves.copy()
|
||||
elif target == "villagers":
|
||||
choice = villagers.copy()
|
||||
evt = Event("vg_kill", {"pl": choice})
|
||||
evt.dispatch(cli, var, ghost, target)
|
||||
choice = evt.data["pl"]
|
||||
# roll this into the above event once succubus is split off
|
||||
if ghost in var.ENTRANCED:
|
||||
choice -= var.ROLES["succubus"]
|
||||
if choice:
|
||||
KILLS[ghost] = random.choice(list(choice))
|
||||
|
||||
@event_listener("transition_day", priority=2)
|
||||
def on_transition_day(evt, cli, var):
|
||||
for k, d in KILLS.items():
|
||||
evt.data["victims"].append(d)
|
||||
evt.data["onlybywolves"].discard(d)
|
||||
evt.data["killers"][d].append(k)
|
||||
|
||||
@event_listener("transition_day", priority=5.01)
|
||||
def on_transition_day2(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
if GHOSTS[k] == "villagers":
|
||||
evt.data["killers"][d].remove(k)
|
||||
evt.data["killers"][d].insert(0, k)
|
||||
# important, otherwise our del_player listener messages the vg
|
||||
del KILLS[k]
|
||||
|
||||
@event_listener("retribution_kill")
|
||||
def on_retribution_kill(evt, cli, var, victim, orig_target):
|
||||
t = evt.data["target"]
|
||||
if t in GHOSTS:
|
||||
GHOSTS[t] = "!" + GHOSTS[t]
|
||||
evt.data["message"].append(messages["totem_banish"].format(victim, t))
|
||||
evt.data["target"] = None
|
||||
|
||||
@event_listener("get_participant_role")
|
||||
def on_get_participant_role(evt, var, nick):
|
||||
if nick in GHOSTS:
|
||||
against = GHOSTS[nick]
|
||||
if against == "villagers":
|
||||
evt.data["role"] = "wolf"
|
||||
elif against == "wolves":
|
||||
evt.data["role"] = "villager"
|
||||
|
||||
@event_listener("chk_nightdone")
|
||||
def on_chk_nightdone(evt, cli, var):
|
||||
evt.data["actedcount"] += len(KILLS)
|
||||
evt.data["nightroles"].extend([p for p in GHOSTS if GHOSTS[p][0] != "!"])
|
||||
|
||||
@event_listener("transition_night_end", priority=2)
|
||||
def on_transition_night_end(evt, cli, var):
|
||||
# alive VGs are messaged as part of villager.py, this handles dead ones
|
||||
ps = list_players()
|
||||
wolves = list_players(var.WOLFTEAM_ROLES)
|
||||
for v_ghost, who in GHOSTS.items():
|
||||
if who[0] == "!":
|
||||
continue
|
||||
if who == "wolves":
|
||||
pl = wolves[:]
|
||||
else:
|
||||
pl = ps[:]
|
||||
for wolf in wolves:
|
||||
pl.remove(wolf)
|
||||
|
||||
random.shuffle(pl)
|
||||
|
||||
if v_ghost in var.PLAYERS and not is_user_simple(v_ghost):
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_notify"].format(who))
|
||||
else:
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_simple"])
|
||||
pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl))
|
||||
debuglog("GHOST: {0} (target: {1}) - players: {2}".format(v_ghost, who, ", ".join(pl)))
|
||||
|
||||
@event_listener("myrole")
|
||||
def on_myrole(evt, cli, var, nick):
|
||||
if nick in GHOSTS:
|
||||
evt.prevent_default = True
|
||||
if GHOSTS[nick][0] != "!":
|
||||
pm(cli, nick, messages["vengeful_role"].format(GHOSTS[nick]))
|
||||
|
||||
@event_listener("revealroles")
|
||||
def on_revealroles(evt, cli, var):
|
||||
if GHOSTS:
|
||||
glist = []
|
||||
for ghost, team in GHOSTS.items():
|
||||
dead = "driven away, " if team[0] == "!" else ""
|
||||
glist.append("{0} ({1}against {2})".format(ghost, dead, team.lstrip("!")))
|
||||
evt.data["output"].append("\u0002dead vengeful ghost\u0002: {0}".format(", ".join(glist)))
|
||||
|
||||
@event_listener("begin_day")
|
||||
def on_begin_day(evt, cli, var):
|
||||
KILLS.clear()
|
||||
|
||||
@event_listener("reset")
|
||||
def on_reset(evt, var):
|
||||
KILLS.clear()
|
||||
GHOSTS.clear()
|
||||
|
||||
# vim: set sw=4 expandtab:
|
@ -97,7 +97,7 @@ def on_transition_day(evt, cli, var):
|
||||
for k, d in list(KILLS.items()):
|
||||
evt.data["victims"].append(d)
|
||||
evt.data["onlybywolves"].discard(d)
|
||||
evt.data["killers"][d] = k
|
||||
evt.data["killers"][d].append(k)
|
||||
# important, otherwise our del_player listener lets hunter kill again
|
||||
del KILLS[k]
|
||||
|
||||
|
@ -91,11 +91,15 @@ def wolf_kill(cli, nick, chan, rest):
|
||||
@cmd("retract", "r", chan=False, pm=True, playing=True, phases=("night",))
|
||||
def wolf_retract(cli, nick, chan, rest):
|
||||
"""Removes a wolf's kill selection."""
|
||||
if nick not in KILLS:
|
||||
return
|
||||
del KILLS[nick]
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
relay_wolfchat_command(cli, nick, messages["wolfchat_retracted_kill"].format(nick), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||
if nick in KILLS:
|
||||
del KILLS[nick]
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
relay_wolfchat_command(cli, nick, messages["wolfchat_retracted_kill"].format(nick), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||
if get_role(nick) == "alpha wolf" and nick in var.BITE_PREFERENCES:
|
||||
del var.BITE_PREFERENCES[nick]
|
||||
var.ALPHA_WOLVES.remove(nick)
|
||||
pm(cli, nick, messages["no_bite"])
|
||||
relay_wolfchat_command(cli, nick, messages["wolfchat_no_bite"].format(nick), ("alpha wolf",), is_wolf_command=True)
|
||||
|
||||
@event_listener("del_player")
|
||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||
@ -170,6 +174,35 @@ def on_transition_day(evt, cli, var):
|
||||
evt.data["bywolves"].discard(monster)
|
||||
evt.data["onlybywolves"].discard(monster)
|
||||
|
||||
@event_listener("transition_day", priority=5)
|
||||
def on_transition_day2(evt, cli, var):
|
||||
wolfteam = list_players(var.WOLFTEAM_ROLES)
|
||||
for victim, killers in list(evt.data["killers"].items()):
|
||||
k2 = []
|
||||
kappend = []
|
||||
wolves = False
|
||||
for k in killers:
|
||||
if k in wolfteam:
|
||||
kappend.append(k)
|
||||
elif k == "@wolves":
|
||||
wolves = True
|
||||
else:
|
||||
k2.append(k)
|
||||
k2.extend(kappend)
|
||||
if wolves:
|
||||
k2.append("@wolves")
|
||||
evt.data["killers"][victim] = k2
|
||||
|
||||
@event_listener("retribution_kill")
|
||||
def on_retribution_kill(evt, cli, var, victim, orig_target):
|
||||
t = evt.data["target"]
|
||||
if t == "@wolves":
|
||||
wolves = list_players(var.WOLF_ROLES)
|
||||
for crow in var.ROLES["werecrow"]:
|
||||
if crow in var.OBSERVED:
|
||||
wolves.remove(crow)
|
||||
evt.data["target"] = random.choice(wolves)
|
||||
|
||||
@event_listener("exchange_roles")
|
||||
def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
|
||||
if actor in KILLS:
|
||||
|
@ -18,8 +18,8 @@ __all__ = ["pm", "is_fake_nick", "mass_mode", "mass_privmsg", "reply",
|
||||
"relay_wolfchat_command", "chk_nightdone", "chk_decision",
|
||||
"chk_win", "irc_lower", "irc_equals", "is_role", "match_hostmask",
|
||||
"is_owner", "is_admin", "plural", "singular", "list_players",
|
||||
"list_players_and_roles", "get_role", "get_reveal_role",
|
||||
"get_templates", "role_order", "break_long_message",
|
||||
"list_players_and_roles", "list_participants", "get_role", "get_roles",
|
||||
"get_reveal_role", "get_templates", "role_order", "break_long_message",
|
||||
"complete_match", "get_victim", "get_nick", "pastebin_tb",
|
||||
"InvalidModeException"]
|
||||
# message either privmsg or notice, depending on user settings
|
||||
@ -309,7 +309,7 @@ def singular(plural):
|
||||
# otherwise we just added an s on the end
|
||||
return plural[:-1]
|
||||
|
||||
def list_players(roles = None):
|
||||
def list_players(roles=None):
|
||||
if roles is None:
|
||||
roles = var.ROLES.keys()
|
||||
pl = set()
|
||||
@ -329,12 +329,28 @@ def list_players_and_roles():
|
||||
plr[p] = x
|
||||
return plr
|
||||
|
||||
def list_participants():
|
||||
"""List all people who are still able to participate in the game in some fashion."""
|
||||
pl = list_players()
|
||||
evt = Event("list_participants", {"pl": pl})
|
||||
evt.dispatch(var)
|
||||
return evt.data["pl"][:]
|
||||
|
||||
def get_role(p):
|
||||
for role, pl in var.ROLES.items():
|
||||
if role in var.TEMPLATE_RESTRICTIONS.keys():
|
||||
continue # only get actual roles
|
||||
if p in pl:
|
||||
return role
|
||||
# not found in player list, see if they're a special participant
|
||||
role = None
|
||||
if p in list_participants():
|
||||
evt = Event("get_participant_role", {"role": None})
|
||||
evt.dispatch(var, p)
|
||||
role = evt.data["role"]
|
||||
if role is None:
|
||||
raise ValueError("Nick {0} isn't playing and has no defined participant role".format(p))
|
||||
return role
|
||||
|
||||
def get_roles(*roles):
|
||||
all_roles = []
|
||||
@ -342,7 +358,6 @@ def get_roles(*roles):
|
||||
all_roles.append(var.ROLES[role])
|
||||
return list(itertools.chain(*all_roles))
|
||||
|
||||
|
||||
def get_reveal_role(nick):
|
||||
if var.HIDDEN_TRAITOR and get_role(nick) == "traitor":
|
||||
role = var.DEFAULT_ROLE
|
||||
|
242
src/wolfgame.py
242
src/wolfgame.py
@ -98,7 +98,6 @@ var.OPPED = False # Keeps track of whether the bot is opped
|
||||
|
||||
var.BITTEN_ROLES = {}
|
||||
var.LYCAN_ROLES = {}
|
||||
var.VENGEFUL_GHOSTS = {}
|
||||
var.CHARMED = set()
|
||||
|
||||
if botconfig.DEBUG_MODE and var.DISABLE_DEBUG_MODE_TIMERS:
|
||||
@ -677,7 +676,7 @@ def replace(cli, nick, chan, rest):
|
||||
|
||||
for user in var.USERS:
|
||||
if irc_lower(var.USERS[user]["account"]) == account:
|
||||
if user == nick or (user not in list_players() and user not in var.VENGEFUL_GHOSTS):
|
||||
if user == nick or user not in list_participants():
|
||||
pass
|
||||
elif target is None:
|
||||
target = user
|
||||
@ -690,7 +689,7 @@ def replace(cli, nick, chan, rest):
|
||||
reply(cli, nick, chan, msg, private=True)
|
||||
return
|
||||
else:
|
||||
pl = list_players() + list(var.VENGEFUL_GHOSTS.keys())
|
||||
pl = list_participants()
|
||||
pll = [irc_lower(i) for i in pl]
|
||||
|
||||
target, _ = complete_match(irc_lower(rest[0]), pll)
|
||||
@ -698,7 +697,7 @@ def replace(cli, nick, chan, rest):
|
||||
if target is not None:
|
||||
target = pl[pll.index(target)]
|
||||
|
||||
if (target not in list_players() and target not in var.VENGEFUL_GHOSTS) or target not in var.USERS:
|
||||
if target not in pl or target not in var.USERS:
|
||||
msg = messages["target_not_playing"].format(" longer" if target in var.DEAD else "t")
|
||||
reply(cli, nick, chan, msg, private=True)
|
||||
return
|
||||
@ -956,9 +955,9 @@ def join_deadchat(cli, *all_nicks):
|
||||
return
|
||||
|
||||
nicks = []
|
||||
pl = list_players()
|
||||
pl = list_participants()
|
||||
for nick in all_nicks:
|
||||
if is_user_stasised(nick) or nick in pl or nick in var.DEADCHAT_PLAYERS or nick in var.VENGEFUL_GHOSTS:
|
||||
if is_user_stasised(nick) or nick in pl or nick in var.DEADCHAT_PLAYERS:
|
||||
continue
|
||||
nicks.append(nick)
|
||||
|
||||
@ -2486,10 +2485,6 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True):
|
||||
pentry["special"].append("lover")
|
||||
if splr in var.ENTRANCED:
|
||||
pentry["special"].append("entranced")
|
||||
if splr in var.VENGEFUL_GHOSTS:
|
||||
pentry["special"].append("vg activated")
|
||||
if var.VENGEFUL_GHOSTS[splr][0] == "!":
|
||||
pentry["special"].append("vg driven off")
|
||||
|
||||
won = False
|
||||
iwon = False
|
||||
@ -2561,29 +2556,6 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True):
|
||||
# For clone, this means they ended game while being clone and not some other role
|
||||
if splr in survived and not winner.startswith("@") and winner not in ("monsters", "demoniacs", "pipers"):
|
||||
iwon = True
|
||||
elif rol == "vengeful ghost":
|
||||
if not winner.startswith("@") and winner not in ("monsters", "demoniacs", "pipers"):
|
||||
if winner != "succubi" and splr in var.ENTRANCED:
|
||||
won = False
|
||||
iwon = False
|
||||
elif won and splr in survived:
|
||||
iwon = True
|
||||
elif splr in var.VENGEFUL_GHOSTS and var.VENGEFUL_GHOSTS[splr] == "villagers" and winner == "wolves":
|
||||
won = True
|
||||
iwon = True
|
||||
elif splr in var.VENGEFUL_GHOSTS and var.VENGEFUL_GHOSTS[splr] == "!villagers" and winner == "wolves":
|
||||
# Starts with ! if they were driven off by retribution totem
|
||||
won = True
|
||||
iwon = False
|
||||
elif splr in var.VENGEFUL_GHOSTS and var.VENGEFUL_GHOSTS[splr] == "wolves" and winner == "villagers":
|
||||
won = True
|
||||
iwon = True
|
||||
elif splr in var.VENGEFUL_GHOSTS and var.VENGEFUL_GHOSTS[splr] == "!wolves" and winner == "villagers":
|
||||
won = True
|
||||
iwon = False
|
||||
else:
|
||||
won = False
|
||||
iwon = False
|
||||
elif rol == "jester" and splr in var.JESTERS:
|
||||
iwon = True
|
||||
elif winner == "succubi" and splr in var.ENTRANCED | var.ROLES["succubus"]:
|
||||
@ -2874,10 +2846,9 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
||||
var.FINAL_ROLES[clone] = nickrole
|
||||
sayrole = nickrole
|
||||
debuglog("{0} (clone) CLONE DEAD PLAYER: {1} ({2})".format(clone, target, sayrole))
|
||||
# if cloning time lord or vengeful ghost, say they are villager instead
|
||||
if sayrole == "time lord":
|
||||
if sayrole in var.HIDDEN_VILLAGERS:
|
||||
sayrole = "villager"
|
||||
elif sayrole == "vengeful ghost":
|
||||
elif sayrole in var.HIDDEN_ROLES:
|
||||
sayrole = var.DEFAULT_ROLE
|
||||
an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else ""
|
||||
pm(cli, clone, messages["clone_turn"].format(an, sayrole))
|
||||
@ -3021,13 +2992,6 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
||||
t.start()
|
||||
|
||||
debuglog(nick, "(time lord) TRIGGER")
|
||||
if nickrole == "vengeful ghost":
|
||||
if killer_role in var.WOLFTEAM_ROLES:
|
||||
var.VENGEFUL_GHOSTS[nick] = "wolves"
|
||||
else:
|
||||
var.VENGEFUL_GHOSTS[nick] = "villagers"
|
||||
pm(cli, nick, messages["vengeful_turn"].format(var.VENGEFUL_GHOSTS[nick]))
|
||||
debuglog(nick, "(vengeful ghost) TRIGGER", var.VENGEFUL_GHOSTS[nick])
|
||||
if nickrole == "wolf cub":
|
||||
var.ANGRY_WOLVES = True
|
||||
if nickrole in var.WOLF_ROLES:
|
||||
@ -3538,7 +3502,7 @@ def rename_player(cli, prefix, nick):
|
||||
dictvar.update(kvp)
|
||||
if prefix in dictvar.keys():
|
||||
del dictvar[prefix]
|
||||
for dictvar in (var.VENGEFUL_GHOSTS, var.TOTEMS, var.FINAL_ROLES, var.GUNNERS, var.TURNCOATS,
|
||||
for dictvar in (var.TOTEMS, var.FINAL_ROLES, var.GUNNERS, var.TURNCOATS,
|
||||
var.DOCTORS, var.BITTEN_ROLES, var.LYCAN_ROLES, var.AMNESIAC_ROLES):
|
||||
if prefix in dictvar.keys():
|
||||
dictvar[nick] = dictvar.pop(prefix)
|
||||
@ -3796,7 +3760,7 @@ def begin_day(cli):
|
||||
|
||||
# Reset nighttime variables
|
||||
var.GAMEPHASE = "day"
|
||||
var.OTHER_KILLS = {} # other kill victims (vengeful ghost)
|
||||
var.OTHER_KILLS = {}
|
||||
var.KILLER = "" # nickname of who chose the victim
|
||||
var.SEEN = set() # set of doomsayers that have had visions
|
||||
var.HEXED = set() # set of hags that have silenced others
|
||||
@ -3901,21 +3865,6 @@ def transition_day(cli, gameid=0):
|
||||
# NOTE: Random assassin selection is further down, since if we're choosing at random we pick someone
|
||||
# that isn't going to be dying today, meaning we need to know who is dying first :)
|
||||
|
||||
# Select a random target for vengeful ghost if they didn't kill
|
||||
wolves = set(list_players(var.WOLFTEAM_ROLES))
|
||||
villagers = set(list_players()) - wolves
|
||||
for ghost, target in var.VENGEFUL_GHOSTS.items():
|
||||
if target[0] == "!" or ghost in var.SILENCED:
|
||||
continue
|
||||
if ghost not in var.OTHER_KILLS:
|
||||
if target == "wolves":
|
||||
choice = wolves.copy()
|
||||
else:
|
||||
choice = villagers.copy()
|
||||
if ghost in var.ENTRANCED:
|
||||
choice -= var.ROLES["succubus"]
|
||||
var.OTHER_KILLS[ghost] = random.choice(list(choice))
|
||||
|
||||
# Select random totem recipients if shamans didn't act
|
||||
shamans = list_players(var.TOTEM_ORDER)
|
||||
for shaman in shamans:
|
||||
@ -4096,7 +4045,6 @@ def transition_day(cli, gameid=0):
|
||||
protected = evt.data["protected"]
|
||||
bitten = evt.data["bitten"]
|
||||
|
||||
wolfghostvictims = []
|
||||
for k, d in var.OTHER_KILLS.items():
|
||||
victims.append(d)
|
||||
onlybywolves.discard(d)
|
||||
@ -4425,17 +4373,13 @@ def transition_day(cli, gameid=0):
|
||||
break
|
||||
if loser in dead or victim == loser:
|
||||
loser = None
|
||||
if loser == "@wolves":
|
||||
wolves = list_players(var.WOLF_ROLES)
|
||||
for crow in var.ROLES["werecrow"]:
|
||||
if crow in var.OBSERVED:
|
||||
wolves.remove(crow)
|
||||
loser = random.choice(wolves)
|
||||
if loser in var.VENGEFUL_GHOSTS.keys():
|
||||
# mark ghost as being unable to kill any more
|
||||
var.VENGEFUL_GHOSTS[loser] = "!" + var.VENGEFUL_GHOSTS[loser]
|
||||
message.append(messages["totem_banish"].format(victim, loser))
|
||||
elif loser is not None and loser not in var.ROLES["blessed villager"]:
|
||||
evt = Event("retribution_kill", {"target": loser, "message": []})
|
||||
evt.dispatch(cli, var, victim, loser)
|
||||
loser = evt.data["target"]
|
||||
message.extend(evt.data["message"])
|
||||
if loser in dead or victim == loser:
|
||||
loser = None
|
||||
if loser is not None and loser not in var.ROLES["blessed villager"]:
|
||||
dead.append(loser)
|
||||
if var.ROLE_REVEAL in ("on", "team"):
|
||||
role = get_reveal_role(loser)
|
||||
@ -4598,13 +4542,20 @@ def transition_day(cli, gameid=0):
|
||||
var.FINAL_ROLES[chump] = newrole
|
||||
relay_wolfchat_command(cli, chump, messages["wolfchat_new_member"].format(chump, newrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||
|
||||
for deadperson in dead: # kill each player, but don't end the game if one group outnumbers another
|
||||
# take a shortcut for killer_role here since vengeful ghost only cares about team and not particular roles
|
||||
# this will have to be modified to track the actual killer if that behavior changes
|
||||
# we check if they have already been killed as well since del_player could do chain reactions and we want
|
||||
for deadperson in dead:
|
||||
# check if they have already been killed since del_player could do chain reactions and we want
|
||||
# to avoid sending duplicate messages.
|
||||
if deadperson in list_players():
|
||||
del_player(cli, deadperson, end_game=False, killer_role="wolf" if deadperson in onlybywolves or deadperson in wolfghostvictims else "villager", deadlist=dead, original=deadperson)
|
||||
if deadperson in killers:
|
||||
killer = killers[deadperson][0]
|
||||
if killer == "@wolves":
|
||||
killer_role = "wolf"
|
||||
else:
|
||||
killer_role = get_role(killer)
|
||||
else:
|
||||
# no killers, so assume suicide
|
||||
killer_role = get_role(deadperson)
|
||||
del_player(cli, deadperson, end_game=False, killer_role=killer_role, deadlist=dead, original=deadperson)
|
||||
|
||||
message = []
|
||||
|
||||
@ -4642,10 +4593,6 @@ def chk_nightdone(cli):
|
||||
"warlock", "piper", "doomsayer",
|
||||
"prophet", "wolf shaman")
|
||||
|
||||
for ghost, against in var.VENGEFUL_GHOSTS.items():
|
||||
if not against.startswith("!"):
|
||||
nightroles.append(ghost)
|
||||
|
||||
for nick, info in var.PRAYED.items():
|
||||
if info[0] > 0:
|
||||
actedcount += 1
|
||||
@ -4664,9 +4611,6 @@ def chk_nightdone(cli):
|
||||
nightroles.extend(get_roles("alpha wolf"))
|
||||
actedcount += len([p for p in var.ALPHA_WOLVES if p in var.ROLES["alpha wolf"]])
|
||||
|
||||
# but remove all instances of their name if they are silenced
|
||||
nightroles = [p for p in nightroles if p not in var.SILENCED]
|
||||
|
||||
# add in turncoats who should be able to act -- if they passed they're already in var.PASSED
|
||||
# but if they can act they're in var.TURNCOATS where the second tuple item is the current night
|
||||
# (if said tuple item is the previous night, then they are not allowed to act tonight)
|
||||
@ -4683,6 +4627,9 @@ def chk_nightdone(cli):
|
||||
event.dispatch(cli, var)
|
||||
actedcount = event.data["actedcount"]
|
||||
|
||||
# remove all instances of their name if they are silenced (makes implementing the event easier)
|
||||
nightroles = [p for p in nightroles if p not in var.SILENCED]
|
||||
|
||||
if var.PHASE == "night" and actedcount >= len(nightroles):
|
||||
if not event.prevent_default:
|
||||
# check for assassins that have not yet targeted
|
||||
@ -5128,13 +5075,13 @@ def check_exchange(cli, actor, nick):
|
||||
return True
|
||||
return False
|
||||
|
||||
@cmd("retract", "r", pm=True, phases=("day", "night", "join"))
|
||||
@cmd("retract", "r", pm=True, phases=("day", "join"))
|
||||
def retract(cli, nick, chan, rest):
|
||||
"""Takes back your vote during the day (for whom to lynch)."""
|
||||
|
||||
if chan not in (botconfig.CHANNEL, nick):
|
||||
if chan != botconfig.CHANNEL:
|
||||
return
|
||||
if (nick not in var.VENGEFUL_GHOSTS.keys() and nick not in list_players()) or nick in var.DISCONNECTED.keys():
|
||||
if nick not in list_players() or nick in var.DISCONNECTED.keys():
|
||||
return
|
||||
|
||||
with var.GRAVEYARD_LOCK, var.WARNING_LOCK:
|
||||
@ -5151,29 +5098,6 @@ def retract(cli, nick, chan, rest):
|
||||
del var.TIMERS['start_votes']
|
||||
return
|
||||
|
||||
if chan == nick: # PM, use different code
|
||||
role = get_role(nick)
|
||||
if role not in var.WOLF_ROLES - {"wolf cub"} and nick not in var.VENGEFUL_GHOSTS.keys():
|
||||
return
|
||||
if var.PHASE != "night":
|
||||
return
|
||||
if role == "werecrow": # Check if already observed
|
||||
if var.OBSERVED.get(nick):
|
||||
pm(cli, nick, (messages["werecrow_transformed"]))
|
||||
return
|
||||
|
||||
if role not in var.WOLF_ROLES and nick in var.OTHER_KILLS.keys():
|
||||
del var.OTHER_KILLS[nick]
|
||||
pm(cli, nick, messages["retracted_kill"])
|
||||
elif role == "alpha wolf" and nick in var.BITE_PREFERENCES.keys():
|
||||
del var.BITE_PREFERENCES[nick]
|
||||
var.ALPHA_WOLVES.remove(nick)
|
||||
pm(cli, nick, messages["no_bite"])
|
||||
relay_wolfchat_command(cli, nick, messages["wolfchat_no_bite"].format(nick), ("alpha wolf",), is_wolf_command=True)
|
||||
elif role == "alpha wolf" and var.ALPHA_ENABLED:
|
||||
pm(cli, nick, messages["kill_bite_pending"])
|
||||
return
|
||||
|
||||
if var.PHASE != "day":
|
||||
return
|
||||
if nick in var.NO_LYNCH:
|
||||
@ -5282,62 +5206,6 @@ def shoot(cli, nick, chan, rest):
|
||||
def is_safe(nick, victim): # helper function
|
||||
return nick in var.ENTRANCED and victim in var.ROLES["succubus"]
|
||||
|
||||
@cmd("kill", chan=False, pm=True, phases=("night",))
|
||||
def kill(cli, nick, chan, rest):
|
||||
"""Kill a player. Behaviour varies depending on your role."""
|
||||
if (nick not in var.VENGEFUL_GHOSTS.keys() and nick not in list_players()) or nick in var.DISCONNECTED.keys():
|
||||
return
|
||||
try:
|
||||
role = get_role(nick)
|
||||
except KeyError:
|
||||
role = None
|
||||
if nick not in var.VENGEFUL_GHOSTS.keys():
|
||||
return
|
||||
if nick in var.VENGEFUL_GHOSTS.keys() and var.VENGEFUL_GHOSTS[nick][0] == "!":
|
||||
# ghost was driven away by retribution
|
||||
return
|
||||
if nick in var.SILENCED:
|
||||
pm(cli, nick, messages["silenced"])
|
||||
return
|
||||
pieces = re.split(" +",rest)
|
||||
victim = pieces[0]
|
||||
|
||||
victim = get_victim(cli, nick, victim, False)
|
||||
if not victim:
|
||||
return
|
||||
if is_safe(nick, victim):
|
||||
pm(cli, nick, messages["no_acting_on_succubus"].format("kill"))
|
||||
return
|
||||
|
||||
if victim == nick:
|
||||
if nick in var.VENGEFUL_GHOSTS.keys():
|
||||
pm(cli, nick, messages["player_dead"])
|
||||
else:
|
||||
pm(cli, nick, messages["no_suicide"])
|
||||
return
|
||||
|
||||
if nick in var.VENGEFUL_GHOSTS.keys():
|
||||
allwolves = list_players(var.WOLFTEAM_ROLES)
|
||||
if var.VENGEFUL_GHOSTS[nick] == "wolves" and victim not in allwolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_wolf"])
|
||||
return
|
||||
elif var.VENGEFUL_GHOSTS[nick] == "villagers" and victim in allwolves:
|
||||
pm(cli, nick, messages["vengeful_ghost_villager"])
|
||||
return
|
||||
|
||||
rv = choose_target(nick, victim)
|
||||
if nick not in var.VENGEFUL_GHOSTS.keys():
|
||||
if check_exchange(cli, nick, rv):
|
||||
return
|
||||
var.OTHER_KILLS[nick] = rv
|
||||
|
||||
msg = messages["wolf_target"].format(victim)
|
||||
pm(cli, nick, messages["player"].format(msg))
|
||||
|
||||
debuglog("{0} ({1}) KILL: {2} ({3})".format(nick, role, victim, get_role(victim)))
|
||||
|
||||
chk_nightdone(cli)
|
||||
|
||||
@cmd("guard", "protect", "save", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("bodyguard", "guardian angel"))
|
||||
def guard(cli, nick, chan, rest):
|
||||
"""Guard a player, preventing them from being killed that night."""
|
||||
@ -5417,7 +5285,8 @@ def consecrate(cli, nick, chan, rest):
|
||||
# but other roles that do stuff after death or impact dead players should have functionality here as well
|
||||
# (for example, if there was a role that could raise corpses as undead somethings, this would prevent that from working)
|
||||
# regardless if this has any actual effect or not, it still removes the priest from being able to vote
|
||||
if victim in var.VENGEFUL_GHOSTS.keys():
|
||||
from src.roles import vengefulghost
|
||||
if victim in vengefulghost.GHOSTS:
|
||||
var.SILENCED.add(victim)
|
||||
|
||||
var.CONSECRATING.add(nick)
|
||||
@ -6713,26 +6582,6 @@ def transition_night(cli):
|
||||
else:
|
||||
pm(cli, lycan, messages["lycan_simple"])
|
||||
|
||||
for v_ghost, who in var.VENGEFUL_GHOSTS.items():
|
||||
if who[0] == "!":
|
||||
continue
|
||||
wolves = list_players(var.WOLFTEAM_ROLES)
|
||||
if who == "wolves":
|
||||
pl = wolves
|
||||
else:
|
||||
pl = ps[:]
|
||||
for wolf in wolves:
|
||||
pl.remove(wolf)
|
||||
|
||||
random.shuffle(pl)
|
||||
|
||||
if v_ghost in var.PLAYERS and not is_user_simple(v_ghost):
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_notify"].format(who))
|
||||
else:
|
||||
pm(cli, v_ghost, messages["vengeful_ghost_simple"])
|
||||
pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl))
|
||||
debuglog("GHOST: {0} (target: {1}) - players: {2}".format(v_ghost, who, ", ".join(pl)))
|
||||
|
||||
for ass in var.ROLES["assassin"]:
|
||||
if ass in var.TARGETED and var.TARGETED[ass] != None:
|
||||
continue # someone already targeted
|
||||
@ -7040,7 +6889,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
||||
var.OBSERVED = {}
|
||||
var.GUARDED = {}
|
||||
var.HVISITED = {}
|
||||
var.VENGEFUL_GHOSTS = {}
|
||||
var.CLONED = {}
|
||||
var.TARGETED = {}
|
||||
var.LASTGUARDED = {}
|
||||
@ -7853,12 +7701,7 @@ def listroles(cli, nick, chan, rest):
|
||||
def myrole(cli, nick, chan, rest):
|
||||
"""Reminds you of your current role."""
|
||||
|
||||
#special case vengeful ghost (that hasn't been driven away)
|
||||
if nick in var.VENGEFUL_GHOSTS.keys() and var.VENGEFUL_GHOSTS[nick][0] != "!":
|
||||
pm(cli, nick, messages["vengeful_role"].format(var.VENGEFUL_GHOSTS[nick]))
|
||||
return
|
||||
|
||||
ps = list_players()
|
||||
ps = list_participants()
|
||||
if nick not in ps:
|
||||
return
|
||||
|
||||
@ -7869,7 +7712,8 @@ def myrole(cli, nick, chan, rest):
|
||||
role = var.DEFAULT_ROLE
|
||||
|
||||
evt = Event("myrole", {"role": role, "messages": []})
|
||||
evt.dispatch(cli, var, nick)
|
||||
if not evt.dispatch(cli, var, nick):
|
||||
return
|
||||
role = evt.data["role"]
|
||||
|
||||
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
||||
@ -8234,7 +8078,7 @@ def can_run_restricted_cmd(nick):
|
||||
if botconfig.DEBUG_MODE:
|
||||
return True
|
||||
|
||||
pl = list_players() + [vg for (vg, against) in var.VENGEFUL_GHOSTS.items() if not against.startswith("!")]
|
||||
pl = list_participants()
|
||||
|
||||
if nick in pl:
|
||||
return False
|
||||
@ -8382,12 +8226,6 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
||||
elif len(lovers) > 2:
|
||||
output.append("\u0002lovers\u0002: {0}, and {1}".format(", ".join(lovers[0:-1]), lovers[-1]))
|
||||
|
||||
# print out vengeful ghosts, also vengeful ghosts that were driven away by 'retribution' totem
|
||||
if var.VENGEFUL_GHOSTS:
|
||||
output.append("\u0002dead vengeful ghost\u0002: {0}".format(", ".join("{0} ({1}against {2})".format(
|
||||
ghost, team.startswith("!") and "driven away, " or "", team.lstrip("!"))
|
||||
for (ghost, team) in var.VENGEFUL_GHOSTS.items())))
|
||||
|
||||
#show who got immunized
|
||||
if var.IMMUNIZED:
|
||||
output.append("\u0002immunized\u0002: {0}".format(", ".join(var.IMMUNIZED)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user