Split dullahan
Also fix the del_player event to be more sane, and fix some suicide bugs in hunter/vigilante kills.
This commit is contained in:
parent
10dff4a73d
commit
23f27b088a
@ -1,7 +1,10 @@
|
|||||||
# event system
|
# event system
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from types import SimpleNamespace
|
||||||
EVENT_CALLBACKS = defaultdict(list)
|
EVENT_CALLBACKS = defaultdict(list)
|
||||||
|
|
||||||
|
__all__ = ["add_listener", "remove_listener", "Event"]
|
||||||
|
|
||||||
def add_listener(event, callback, priority=5):
|
def add_listener(event, callback, priority=5):
|
||||||
if (priority, callback) not in EVENT_CALLBACKS[event]:
|
if (priority, callback) not in EVENT_CALLBACKS[event]:
|
||||||
EVENT_CALLBACKS[event].append((priority, callback))
|
EVENT_CALLBACKS[event].append((priority, callback))
|
||||||
@ -12,11 +15,12 @@ def remove_listener(event, callback, priority = 5):
|
|||||||
EVENT_CALLBACKS[event].remove((priority, callback))
|
EVENT_CALLBACKS[event].remove((priority, callback))
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
def __init__(self, name, data):
|
def __init__(self, name, data, **kwargs):
|
||||||
self.stop_processing = False
|
self.stop_processing = False
|
||||||
self.prevent_default = False
|
self.prevent_default = False
|
||||||
self.name = name
|
self.name = name
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.params = SimpleNamespace(**kwargs)
|
||||||
|
|
||||||
def dispatch(self, *args, **kwargs):
|
def dispatch(self, *args, **kwargs):
|
||||||
for item in list(EVENT_CALLBACKS[self.name]):
|
for item in list(EVENT_CALLBACKS[self.name]):
|
||||||
|
@ -1103,7 +1103,7 @@ class SleepyMode(GameMode):
|
|||||||
var.DYING.add(self.having_nightmare)
|
var.DYING.add(self.having_nightmare)
|
||||||
pm(cli, self.having_nightmare, messages["sleepy_nightmare_death"])
|
pm(cli, self.having_nightmare, messages["sleepy_nightmare_death"])
|
||||||
|
|
||||||
def happy_fun_times(self, evt, cli, var, nick, nickrole, nicktpls, forced_death, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl):
|
def happy_fun_times(self, evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||||
if death_triggers:
|
if death_triggers:
|
||||||
if nickrole == "priest":
|
if nickrole == "priest":
|
||||||
pl = evt.data["pl"]
|
pl = evt.data["pl"]
|
||||||
|
239
src/roles/dullahan.py
Normal file
239
src/roles/dullahan.py
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
import math
|
||||||
|
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]
|
||||||
|
TARGETS = {} # type: Dict[str, Set[str]]
|
||||||
|
|
||||||
|
@cmd("kill", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("dullahan",))
|
||||||
|
def dullahan_kill(cli, nick, chan, rest):
|
||||||
|
"""Kill someone at night as a dullahan until everyone on your list is dead."""
|
||||||
|
if not TARGETS[nick] & set(list_players()):
|
||||||
|
pm(cli, nick, messages["dullahan_targets_dead"])
|
||||||
|
return
|
||||||
|
|
||||||
|
victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
|
||||||
|
if not victim:
|
||||||
|
return
|
||||||
|
|
||||||
|
if victim == nick:
|
||||||
|
pm(cli, nick, messages["no_suicide"])
|
||||||
|
return
|
||||||
|
|
||||||
|
orig = victim
|
||||||
|
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True})
|
||||||
|
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=True, phases=("night",), roles=("dullahan",))
|
||||||
|
def dullahan_retract(cli, nick, chan, rest):
|
||||||
|
"""Removes a dullahan's kill selection."""
|
||||||
|
if nick not in KILLS:
|
||||||
|
return
|
||||||
|
if nick in KILLS:
|
||||||
|
del KILLS[nick]
|
||||||
|
pm(cli, nick, messages["retracted_kill"])
|
||||||
|
|
||||||
|
@event_listener("player_win")
|
||||||
|
def on_player_win(evt, cli, var, nick, role, winner, survived):
|
||||||
|
if role != "dullahan":
|
||||||
|
return
|
||||||
|
alive = set(list_players())
|
||||||
|
if nick in var.ENTRANCED:
|
||||||
|
alive -= var.ROLES["succubus"]
|
||||||
|
if not TARGETS[nick] & alive:
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
|
||||||
|
@event_listener("del_player")
|
||||||
|
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]
|
||||||
|
elif h == nick:
|
||||||
|
del KILLS[h]
|
||||||
|
if death_triggers and nickrole == "dullahan":
|
||||||
|
pl = evt.data["pl"]
|
||||||
|
targets = TARGETS[nick] & set(pl)
|
||||||
|
if targets:
|
||||||
|
target = random.choice(list(targets))
|
||||||
|
if "totem" in var.ACTIVE_PROTECTIONS[target]:
|
||||||
|
var.ACTIVE_PROTECTIONS[target].remove("totem")
|
||||||
|
cli.msg(botconfig.CHANNEL, messages["dullahan_die_totem"].format(nick, target))
|
||||||
|
elif "angel" in var.ACTIVE_PROTECTIONS[target]:
|
||||||
|
var.ACTIVE_PROTECTIONS[target].remove("angel")
|
||||||
|
cli.msg(botconfig.CHANNEL, messages["dullahan_die_angel"].format(nick, target))
|
||||||
|
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target]:
|
||||||
|
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
|
||||||
|
for bg in var.ROLES["bodyguard"]:
|
||||||
|
if var.GUARDED.get(bg) == target:
|
||||||
|
cli.msg(botconfig.CHANNEL, messages["dullahan_die_bodyguard"].format(nick, target, bg))
|
||||||
|
evt.params.del_player(cli, bg, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
|
||||||
|
evt.data["pl"] = evt.params.refresh_pl(pl)
|
||||||
|
break
|
||||||
|
elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]):
|
||||||
|
if "blessing" in var.ACTIVE_PROTECTIONS[target]:
|
||||||
|
var.ACTIVE_PROTECTIONS[target].remove("blessing")
|
||||||
|
# don't message the channel whenever a blessing blocks a kill, but *do* let the dullahan know so they don't try to report it as a bug
|
||||||
|
pm(cli, nick, messages["assassin_fail_blessed"].format(target))
|
||||||
|
else:
|
||||||
|
if var.ROLE_REVEAL in ("on", "team"):
|
||||||
|
role = get_reveal_role(target)
|
||||||
|
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
|
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success"].format(nick, target, an, role))
|
||||||
|
else:
|
||||||
|
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success_noreveal"].format(nick, target))
|
||||||
|
debuglog("{0} ({1}) DULLAHAN ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
|
||||||
|
evt.params.del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
|
||||||
|
evt.data["pl"] = evt.params.refresh_pl(pl)
|
||||||
|
|
||||||
|
@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]
|
||||||
|
kvp = []
|
||||||
|
for a,b in TARGETS.items():
|
||||||
|
nl = set()
|
||||||
|
for n in b:
|
||||||
|
if n == prefix:
|
||||||
|
n = nick
|
||||||
|
nl.add(n)
|
||||||
|
if a == prefix:
|
||||||
|
a = nick
|
||||||
|
kvp.append((a,nl))
|
||||||
|
TARGETS.update(kvp)
|
||||||
|
if prefix in TARGETS:
|
||||||
|
del TARGETS[prefix]
|
||||||
|
|
||||||
|
@event_listener("acted")
|
||||||
|
def on_acted(evt, cli, var, nick, sender):
|
||||||
|
if nick in KILLS:
|
||||||
|
evt.data["acted"] = True
|
||||||
|
|
||||||
|
@event_listener("transition_day", priority=2)
|
||||||
|
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
|
||||||
|
del KILLS[k]
|
||||||
|
|
||||||
|
@event_listener("exchange_roles")
|
||||||
|
def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
|
||||||
|
if actor in KILLS:
|
||||||
|
del KILLS[actor]
|
||||||
|
if nick in KILLS:
|
||||||
|
del KILLS[nick]
|
||||||
|
if actor_role == "dullahan" and nick_role != "dullahan" and actor in TARGETS:
|
||||||
|
TARGETS[nick] = TARGETS[actor] - {nick}
|
||||||
|
del TARGETS[actor]
|
||||||
|
elif nick_role == "dullahan" and actor_role != "dullahan" and nick in TARGETS:
|
||||||
|
TARGETS[actor] = TARGETS[nick] - {actor}
|
||||||
|
del TARGETS[nick]
|
||||||
|
|
||||||
|
@event_listener("chk_nightdone")
|
||||||
|
def on_chk_nightdone(evt, cli, var):
|
||||||
|
spl = set(list_players())
|
||||||
|
evt.data["actedcount"] += len(KILLS)
|
||||||
|
for p in var.ROLES["dullahan"]:
|
||||||
|
if TARGETS[p] & spl:
|
||||||
|
evt.data["nightroles"].append(p)
|
||||||
|
|
||||||
|
@event_listener("transition_night_end", priority=2)
|
||||||
|
def on_transition_night_end(evt, cli, var):
|
||||||
|
for dullahan in var.ROLES["dullahan"]:
|
||||||
|
targets = list(TARGETS[dullahan])
|
||||||
|
for target in var.DEAD:
|
||||||
|
if target in targets:
|
||||||
|
targets.remove(target)
|
||||||
|
if not targets: # already all dead
|
||||||
|
pm(cli, dullahan, messages["dullahan_targets_dead"])
|
||||||
|
continue
|
||||||
|
random.shuffle(targets)
|
||||||
|
if dullahan in var.PLAYERS and not is_user_simple(dullahan):
|
||||||
|
pm(cli, dullahan, messages["dullahan_notify"])
|
||||||
|
else:
|
||||||
|
pm(cli, dullahan, messages["dullahan_simple"])
|
||||||
|
t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"]
|
||||||
|
pm(cli, dullahan, t + ", ".join(targets))
|
||||||
|
|
||||||
|
@event_listener("role_assignment")
|
||||||
|
def on_role_assignment(evt, cli, var, gamemode, pl, restart):
|
||||||
|
# assign random targets to dullahan to kill
|
||||||
|
if var.ROLES["dullahan"]:
|
||||||
|
max_targets = math.ceil(8.1 * math.log(len(pl), 10) - 5)
|
||||||
|
for dull in var.ROLES["dullahan"]:
|
||||||
|
TARGETS[dull] = set()
|
||||||
|
dull_targets = Event("dullahan_targets", {"targets": TARGETS}) # support sleepy
|
||||||
|
dull_targets.dispatch(cli, var, var.ROLES["dullahan"], max_targets)
|
||||||
|
|
||||||
|
for dull, ts in TARGETS.items():
|
||||||
|
ps = pl[:]
|
||||||
|
ps.remove(dull)
|
||||||
|
while len(ts) < max_targets:
|
||||||
|
target = random.choice(ps)
|
||||||
|
ps.remove(target)
|
||||||
|
ts.add(target)
|
||||||
|
|
||||||
|
@event_listener("myrole")
|
||||||
|
def on_myrole(evt, cli, var, nick):
|
||||||
|
role = get_role(nick)
|
||||||
|
# Remind dullahans of their targets
|
||||||
|
if role == "dullahan":
|
||||||
|
targets = list(TARGETS[nick])
|
||||||
|
for target in var.DEAD:
|
||||||
|
if target in targets:
|
||||||
|
targets.remove(target)
|
||||||
|
random.shuffle(targets)
|
||||||
|
if targets:
|
||||||
|
t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"]
|
||||||
|
evt.data["messages"].append(t + ", ".join(targets))
|
||||||
|
else:
|
||||||
|
evt.data["messages"].append(messages["dullahan_targets_dead"])
|
||||||
|
|
||||||
|
@event_listener("revealroles_role")
|
||||||
|
def on_revealroles_role(evt, cli, var, nickname, role):
|
||||||
|
if role == "dullahan" and nickname in TARGETS:
|
||||||
|
targets = TARGETS[nickname] - var.DEAD
|
||||||
|
if targets:
|
||||||
|
evt.data["special_case"].append("need to kill {0}".format(", ".join(TARGETS[nickname] - var.DEAD)))
|
||||||
|
else:
|
||||||
|
evt.data["special_case"].append("All targets dead")
|
||||||
|
|
||||||
|
@event_listener("begin_day")
|
||||||
|
def on_begin_day(evt, cli, var):
|
||||||
|
KILLS.clear()
|
||||||
|
|
||||||
|
@event_listener("reset")
|
||||||
|
def on_reset(evt, var):
|
||||||
|
KILLS.clear()
|
||||||
|
TARGETS.clear()
|
||||||
|
|
||||||
|
# vim: set sw=4 expandtab:
|
@ -23,6 +23,10 @@ def hunter_kill(cli, nick, chan, rest):
|
|||||||
if not victim:
|
if not victim:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if victim == nick:
|
||||||
|
pm(cli, nick, messages["no_suicide"])
|
||||||
|
return
|
||||||
|
|
||||||
orig = victim
|
orig = victim
|
||||||
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True})
|
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True})
|
||||||
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
||||||
@ -67,7 +71,7 @@ def hunter_pass(cli, nick, chan, rest):
|
|||||||
chk_nightdone(cli)
|
chk_nightdone(cli)
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, lynched, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl):
|
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||||
for h,v in list(KILLS.items()):
|
for h,v in list(KILLS.items()):
|
||||||
if v == nick:
|
if v == nick:
|
||||||
HUNTERS.discard(h)
|
HUNTERS.discard(h)
|
||||||
|
@ -19,6 +19,10 @@ def vigilante_kill(cli, nick, chan, rest):
|
|||||||
if not victim:
|
if not victim:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if victim == nick:
|
||||||
|
pm(cli, nick, messages["no_suicide"])
|
||||||
|
return
|
||||||
|
|
||||||
orig = victim
|
orig = victim
|
||||||
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True})
|
evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True})
|
||||||
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
|
||||||
@ -58,7 +62,7 @@ def vigilante_pass(cli, nick, chan, rest):
|
|||||||
chk_nightdone(cli)
|
chk_nightdone(cli)
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, lynched, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl):
|
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||||
for h,v in list(KILLS.items()):
|
for h,v in list(KILLS.items()):
|
||||||
if v == nick:
|
if v == nick:
|
||||||
PASSED.discard(h)
|
PASSED.discard(h)
|
||||||
|
@ -73,7 +73,7 @@ def on_myrole(evt, cli, var, nick):
|
|||||||
evt.data["messages"].append(messages["wild_child_idol"].format(IDOLS[nick]))
|
evt.data["messages"].append(messages["wild_child_idol"].format(IDOLS[nick]))
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, lynched, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl):
|
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||||
if var.PHASE not in var.GAME_PHASES:
|
if var.PHASE not in var.GAME_PHASES:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -86,7 +86,14 @@ def on_del_player(evt, cli, var, nick, nickrole, nicktpls, lynched, end_game, de
|
|||||||
var.ROLES["wild child"].remove(child)
|
var.ROLES["wild child"].remove(child)
|
||||||
var.ROLES["wolf"].add(child)
|
var.ROLES["wolf"].add(child)
|
||||||
var.FINAL_ROLES[child] = "wolf"
|
var.FINAL_ROLES[child] = "wolf"
|
||||||
wolves = list_players(var.WOLFCHAT_ROLES)
|
|
||||||
|
wcroles = var.WOLFCHAT_ROLES
|
||||||
|
if var.RESTRICT_WOLFCHAT & var.RW_REM_NON_WOLVES:
|
||||||
|
if var.RESTRICT_WOLFCHAT & var.RW_TRAITOR_NON_WOLF:
|
||||||
|
wcroles = var.WOLF_ROLES
|
||||||
|
else:
|
||||||
|
wcroles = var.WOLF_ROLES | {"traitor"}
|
||||||
|
wolves = list_players(wc)
|
||||||
wolves.remove(child)
|
wolves.remove(child)
|
||||||
mass_privmsg(cli, wolves, messages["wild_child_as_wolf"].format(child))
|
mass_privmsg(cli, wolves, messages["wild_child_as_wolf"].format(child))
|
||||||
if var.PHASE == "day":
|
if var.PHASE == "day":
|
||||||
|
@ -98,7 +98,7 @@ def wolf_retract(cli, nick, chan, rest):
|
|||||||
relay_wolfchat_command(cli, nick, messages["wolfchat_retracted_kill"].format(nick), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
|
relay_wolfchat_command(cli, nick, messages["wolfchat_retracted_kill"].format(nick), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, lynched, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl):
|
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
|
||||||
for a,b in list(KILLS.items()):
|
for a,b in list(KILLS.items()):
|
||||||
for n in b:
|
for n in b:
|
||||||
if n == nick:
|
if n == nick:
|
||||||
|
117
src/wolfgame.py
117
src/wolfgame.py
@ -2586,8 +2586,6 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True):
|
|||||||
iwon = False
|
iwon = False
|
||||||
elif rol == "jester" and splr in var.JESTERS:
|
elif rol == "jester" and splr in var.JESTERS:
|
||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "dullahan" and not var.DULLAHAN_TARGETS[splr] & set(survived) - (var.ROLES["succubus"] if splr in var.ENTRANCED else set()):
|
|
||||||
iwon = True
|
|
||||||
elif winner == "succubi" and splr in var.ENTRANCED | var.ROLES["succubus"]:
|
elif winner == "succubi" and splr in var.ENTRANCED | var.ROLES["succubus"]:
|
||||||
iwon = True
|
iwon = True
|
||||||
elif not iwon:
|
elif not iwon:
|
||||||
@ -2973,39 +2971,6 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
|||||||
debuglog("{0} ({1}) ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
|
debuglog("{0} ({1}) ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
|
||||||
del_player(cli, target, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False)
|
del_player(cli, target, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False)
|
||||||
pl = refresh_pl(pl)
|
pl = refresh_pl(pl)
|
||||||
if nickrole == "dullahan":
|
|
||||||
targets = var.DULLAHAN_TARGETS[nick] & set(pl)
|
|
||||||
if targets:
|
|
||||||
target = random.choice(list(targets))
|
|
||||||
if "totem" in var.ACTIVE_PROTECTIONS[target]:
|
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("totem")
|
|
||||||
cli.msg(botconfig.CHANNEL, messages["dullahan_die_totem"].format(nick, target))
|
|
||||||
elif "angel" in var.ACTIVE_PROTECTIONS[target]:
|
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("angel")
|
|
||||||
cli.msg(botconfig.CHANNEL, messages["dullahan_die_angel"].format(nick, target))
|
|
||||||
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target]:
|
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
|
|
||||||
for bg in var.ROLES["bodyguard"]:
|
|
||||||
if var.GUARDED.get(bg) == target:
|
|
||||||
cli.msg(botconfig.CHANNEL, messages["dullahan_die_bodyguard"].format(nick, target, bg))
|
|
||||||
del_player(cli, bg, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False)
|
|
||||||
pl = refresh_pl(pl)
|
|
||||||
break
|
|
||||||
elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]):
|
|
||||||
if "blessing" in var.ACTIVE_PROTECTIONS[target]:
|
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("blessing")
|
|
||||||
# don't message the channel whenever a blessing blocks a kill, but *do* let the dullahan know so they don't try to report it as a bug
|
|
||||||
pm(cli, nick, messages["assassin_fail_blessed"].format(target))
|
|
||||||
else:
|
|
||||||
if var.ROLE_REVEAL in ("on", "team"):
|
|
||||||
role = get_reveal_role(target)
|
|
||||||
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success"].format(nick, target, an, role))
|
|
||||||
else:
|
|
||||||
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success_noreveal"].format(nick, target))
|
|
||||||
debuglog("{0} ({1}) DULLAHAN ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
|
|
||||||
del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False)
|
|
||||||
pl = refresh_pl(pl)
|
|
||||||
if nickrole == "time lord":
|
if nickrole == "time lord":
|
||||||
if "DAY_TIME_LIMIT" not in var.ORIGINAL_SETTINGS:
|
if "DAY_TIME_LIMIT" not in var.ORIGINAL_SETTINGS:
|
||||||
var.ORIGINAL_SETTINGS["DAY_TIME_LIMIT"] = var.DAY_TIME_LIMIT
|
var.ORIGINAL_SETTINGS["DAY_TIME_LIMIT"] = var.DAY_TIME_LIMIT
|
||||||
@ -3149,8 +3114,13 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
|||||||
debuglog(nick, "(mad scientist) KILL FAIL")
|
debuglog(nick, "(mad scientist) KILL FAIL")
|
||||||
|
|
||||||
pl = refresh_pl(pl)
|
pl = refresh_pl(pl)
|
||||||
event = Event("del_player", {"pl": pl})
|
# i herd u liek parameters
|
||||||
event.dispatch(cli, var, nick, nickrole, nicktpls, forced_death, end_game, death_triggers and var.PHASE in var.GAME_PHASES, killer_role, deadlist, original, ismain, refresh_pl)
|
evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
|
||||||
|
event = Event("del_player", {"pl": pl},
|
||||||
|
forced_death=forced_death, end_game=end_game,
|
||||||
|
deadlist=deadlist, original=original, killer_role=killer_role,
|
||||||
|
ismain=ismain, refresh_pl=refresh_pl, del_player=del_player)
|
||||||
|
event.dispatch(cli, var, nick, nickrole, nicktpls, evt_death_triggers)
|
||||||
|
|
||||||
if devoice and (var.PHASE != "night" or not var.DEVOICE_DURING_NIGHT):
|
if devoice and (var.PHASE != "night" or not var.DEVOICE_DURING_NIGHT):
|
||||||
cmode.append(("-v", nick))
|
cmode.append(("-v", nick))
|
||||||
@ -3573,7 +3543,7 @@ def rename_player(cli, prefix, nick):
|
|||||||
if prefix in dictvar.keys():
|
if prefix in dictvar.keys():
|
||||||
dictvar[nick] = dictvar.pop(prefix)
|
dictvar[nick] = dictvar.pop(prefix)
|
||||||
# Looks like {'6': {'jacob3'}, 'jacob3': {'6'}}
|
# Looks like {'6': {'jacob3'}, 'jacob3': {'6'}}
|
||||||
for dictvar in (var.LOVERS, var.ORIGINAL_LOVERS, var.DULLAHAN_TARGETS):
|
for dictvar in (var.LOVERS, var.ORIGINAL_LOVERS):
|
||||||
kvp = []
|
kvp = []
|
||||||
for a,b in dictvar.items():
|
for a,b in dictvar.items():
|
||||||
nl = set()
|
nl = set()
|
||||||
@ -3826,7 +3796,7 @@ def begin_day(cli):
|
|||||||
|
|
||||||
# Reset nighttime variables
|
# Reset nighttime variables
|
||||||
var.GAMEPHASE = "day"
|
var.GAMEPHASE = "day"
|
||||||
var.OTHER_KILLS = {} # other kill victims (dullahan/vengeful ghost)
|
var.OTHER_KILLS = {} # other kill victims (vengeful ghost)
|
||||||
var.KILLER = "" # nickname of who chose the victim
|
var.KILLER = "" # nickname of who chose the victim
|
||||||
var.SEEN = set() # set of doomsayers that have had visions
|
var.SEEN = set() # set of doomsayers that have had visions
|
||||||
var.HEXED = set() # set of hags that have silenced others
|
var.HEXED = set() # set of hags that have silenced others
|
||||||
@ -4685,11 +4655,6 @@ def chk_nightdone(cli):
|
|||||||
# don't count this twice
|
# don't count this twice
|
||||||
actedcount -= 1
|
actedcount -= 1
|
||||||
|
|
||||||
for p in var.ROLES["dullahan"]:
|
|
||||||
# dullahans without targets cannot act, so don't count them
|
|
||||||
if var.DULLAHAN_TARGETS[p] & spl:
|
|
||||||
nightroles.append(p)
|
|
||||||
|
|
||||||
if var.FIRST_NIGHT:
|
if var.FIRST_NIGHT:
|
||||||
actedcount += len(var.MATCHMAKERS | var.CLONED.keys())
|
actedcount += len(var.MATCHMAKERS | var.CLONED.keys())
|
||||||
nightroles.extend(get_roles("matchmaker", "clone"))
|
nightroles.extend(get_roles("matchmaker", "clone"))
|
||||||
@ -5328,15 +5293,11 @@ def kill(cli, nick, chan, rest):
|
|||||||
role = get_role(nick)
|
role = get_role(nick)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
role = None
|
role = None
|
||||||
if role != "dullahan" and nick not in var.VENGEFUL_GHOSTS.keys():
|
if nick not in var.VENGEFUL_GHOSTS.keys():
|
||||||
return
|
return
|
||||||
if nick in var.VENGEFUL_GHOSTS.keys() and var.VENGEFUL_GHOSTS[nick][0] == "!":
|
if nick in var.VENGEFUL_GHOSTS.keys() and var.VENGEFUL_GHOSTS[nick][0] == "!":
|
||||||
# ghost was driven away by retribution
|
# ghost was driven away by retribution
|
||||||
return
|
return
|
||||||
if role == "dullahan" and not var.DULLAHAN_TARGETS[nick] & set(list_players()):
|
|
||||||
# all their targets are dead
|
|
||||||
pm(cli, nick, messages["dullahan_targets_dead"])
|
|
||||||
return
|
|
||||||
if nick in var.SILENCED:
|
if nick in var.SILENCED:
|
||||||
pm(cli, nick, messages["silenced"])
|
pm(cli, nick, messages["silenced"])
|
||||||
return
|
return
|
||||||
@ -5713,7 +5674,7 @@ def hvisit(cli, nick, chan, rest):
|
|||||||
var.HEXED.remove(victim)
|
var.HEXED.remove(victim)
|
||||||
del var.LASTHEXED[victim]
|
del var.LASTHEXED[victim]
|
||||||
# temp hack, will do something better once succubus is split off
|
# temp hack, will do something better once succubus is split off
|
||||||
from src.roles import wolf, hunter
|
from src.roles import wolf, hunter, dullahan
|
||||||
if set(wolf.KILLS.get(victim, ())) & var.ROLES["succubus"]:
|
if set(wolf.KILLS.get(victim, ())) & var.ROLES["succubus"]:
|
||||||
for s in var.ROLES["succubus"]:
|
for s in var.ROLES["succubus"]:
|
||||||
if s in wolf.KILLS[victim]:
|
if s in wolf.KILLS[victim]:
|
||||||
@ -5728,8 +5689,10 @@ def hvisit(cli, nick, chan, rest):
|
|||||||
if var.BITE_PREFERENCES.get(victim) in var.ROLES["succubus"]:
|
if var.BITE_PREFERENCES.get(victim) in var.ROLES["succubus"]:
|
||||||
pm(cli, victim, messages["no_kill_succubus"].format(var.BITE_PREFERENCES[victim]))
|
pm(cli, victim, messages["no_kill_succubus"].format(var.BITE_PREFERENCES[victim]))
|
||||||
del var.BITE_PREFERENCES[victim]
|
del var.BITE_PREFERENCES[victim]
|
||||||
if var.DULLAHAN_TARGETS.get(victim, set()) & var.ROLES["succubus"]:
|
if dullahan.TARGETS.get(victim, set()) & var.ROLES["succubus"]:
|
||||||
pm(cli, victim, messages["dullahan_no_kill_succubus"])
|
pm(cli, victim, messages["dullahan_no_kill_succubus"])
|
||||||
|
if dullahan.KILLS.get(victim) in var.ROLES["succubus"]:
|
||||||
|
del dullahan.KILLS[victim]
|
||||||
|
|
||||||
debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, role, victim, get_role(victim)))
|
debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, role, victim, get_role(victim)))
|
||||||
chk_nightdone(cli)
|
chk_nightdone(cli)
|
||||||
@ -6671,22 +6634,6 @@ def transition_night(cli):
|
|||||||
if role not in var.WOLFCHAT_ROLES:
|
if role not in var.WOLFCHAT_ROLES:
|
||||||
pm(cli, shaman, "Players: " + ", ".join(pl))
|
pm(cli, shaman, "Players: " + ", ".join(pl))
|
||||||
|
|
||||||
for dullahan in var.ROLES["dullahan"]:
|
|
||||||
targets = list(var.DULLAHAN_TARGETS[dullahan])
|
|
||||||
for target in var.DEAD:
|
|
||||||
if target in targets:
|
|
||||||
targets.remove(target)
|
|
||||||
if not targets: # already all dead
|
|
||||||
pm(cli, dullahan, messages["dullahan_targets_dead"])
|
|
||||||
continue
|
|
||||||
random.shuffle(targets)
|
|
||||||
if dullahan in var.PLAYERS and not is_user_simple(dullahan):
|
|
||||||
pm(cli, dullahan, messages["dullahan_notify"])
|
|
||||||
else:
|
|
||||||
pm(cli, dullahan, messages["dullahan_simple"])
|
|
||||||
t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"]
|
|
||||||
pm(cli, dullahan, t + ", ".join(targets))
|
|
||||||
|
|
||||||
for succubus in var.ROLES["succubus"]:
|
for succubus in var.ROLES["succubus"]:
|
||||||
pl = ps[:]
|
pl = ps[:]
|
||||||
random.shuffle(pl)
|
random.shuffle(pl)
|
||||||
@ -7160,7 +7107,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.DYING = set()
|
var.DYING = set()
|
||||||
var.PRAYED = {}
|
var.PRAYED = {}
|
||||||
var.SICK = set()
|
var.SICK = set()
|
||||||
var.DULLAHAN_TARGETS = {}
|
|
||||||
var.DECEIVED = set()
|
var.DECEIVED = set()
|
||||||
|
|
||||||
var.DEADCHAT_PLAYERS = set()
|
var.DEADCHAT_PLAYERS = set()
|
||||||
@ -7236,20 +7182,8 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.LAST_TIME = None
|
var.LAST_TIME = None
|
||||||
var.LAST_VOTES = None
|
var.LAST_VOTES = None
|
||||||
|
|
||||||
if var.ROLES["dullahan"]: # assign random targets to dullahan to kill
|
event = Event("role_assignment", {})
|
||||||
max_targets = math.ceil(8.1 * math.log(len(pl), 10) - 5)
|
event.dispatch(cli, var, var.CURRENT_GAMEMODE.name, pl[:], restart)
|
||||||
for dull in var.ROLES["dullahan"]:
|
|
||||||
var.DULLAHAN_TARGETS[dull] = set()
|
|
||||||
dull_targets = Event("dullahan_targets", {"targets": var.DULLAHAN_TARGETS}) # support sleepy
|
|
||||||
dull_targets.dispatch(cli, var, var.ROLES["dullahan"], max_targets)
|
|
||||||
|
|
||||||
for dull, ts in var.DULLAHAN_TARGETS.items():
|
|
||||||
ps = pl[:]
|
|
||||||
ps.remove(dull)
|
|
||||||
while len(ts) < max_targets:
|
|
||||||
target = random.choice(ps)
|
|
||||||
ps.remove(target)
|
|
||||||
ts.add(target)
|
|
||||||
|
|
||||||
if not restart:
|
if not restart:
|
||||||
gamemode = var.CURRENT_GAMEMODE.name
|
gamemode = var.CURRENT_GAMEMODE.name
|
||||||
@ -7968,19 +7902,6 @@ def myrole(cli, nick, chan, rest):
|
|||||||
if role == "turncoat":
|
if role == "turncoat":
|
||||||
pm(cli, nick, messages["turncoat_side"].format(var.TURNCOATS.get(nick, "none")[0]))
|
pm(cli, nick, messages["turncoat_side"].format(var.TURNCOATS.get(nick, "none")[0]))
|
||||||
|
|
||||||
# Remind dullahans of their targets
|
|
||||||
if role == "dullahan":
|
|
||||||
targets = list(var.DULLAHAN_TARGETS[nick])
|
|
||||||
for target in var.DEAD:
|
|
||||||
if target in targets:
|
|
||||||
targets.remove(target)
|
|
||||||
random.shuffle(targets)
|
|
||||||
if targets:
|
|
||||||
t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"]
|
|
||||||
pm(cli, nick, t + ", ".join(targets))
|
|
||||||
else:
|
|
||||||
pm(cli, nick, messages["dullahan_targets_dead"])
|
|
||||||
|
|
||||||
# Check for gun/bullets
|
# Check for gun/bullets
|
||||||
if nick not in var.ROLES["amnesiac"] and nick in var.GUNNERS and var.GUNNERS[nick]:
|
if nick not in var.ROLES["amnesiac"] and nick in var.GUNNERS and var.GUNNERS[nick]:
|
||||||
role = "gunner"
|
role = "gunner"
|
||||||
@ -8433,12 +8354,6 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
|
|||||||
elif role == "turncoat" and nickname in var.TURNCOATS:
|
elif role == "turncoat" and nickname in var.TURNCOATS:
|
||||||
special_case.append("currently with \u0002{0}\u0002".format(var.TURNCOATS[nickname][0])
|
special_case.append("currently with \u0002{0}\u0002".format(var.TURNCOATS[nickname][0])
|
||||||
if var.TURNCOATS[nickname][0] != "none" else "not currently on any side")
|
if var.TURNCOATS[nickname][0] != "none" else "not currently on any side")
|
||||||
elif role == "dullahan" and nickname in var.DULLAHAN_TARGETS:
|
|
||||||
targets = var.DULLAHAN_TARGETS[nickname] - var.DEAD
|
|
||||||
if targets:
|
|
||||||
special_case.append("need to kill {0}".format(", ".join(var.DULLAHAN_TARGETS[nickname] - var.DEAD)))
|
|
||||||
else:
|
|
||||||
special_case.append("All targets dead")
|
|
||||||
|
|
||||||
evt = Event("revealroles_role", {"special_case": special_case})
|
evt = Event("revealroles_role", {"special_case": special_case})
|
||||||
evt.dispatch(cli, var, nickname, role)
|
evt.dispatch(cli, var, nickname, role)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user