diff --git a/src/events.py b/src/events.py index c712ac4..00863d8 100644 --- a/src/events.py +++ b/src/events.py @@ -1,7 +1,10 @@ # event system from collections import defaultdict +from types import SimpleNamespace EVENT_CALLBACKS = defaultdict(list) +__all__ = ["add_listener", "remove_listener", "Event"] + def add_listener(event, callback, priority=5): if (priority, callback) not in EVENT_CALLBACKS[event]: EVENT_CALLBACKS[event].append((priority, callback)) @@ -12,11 +15,12 @@ def remove_listener(event, callback, priority = 5): EVENT_CALLBACKS[event].remove((priority, callback)) class Event: - def __init__(self, name, data): + def __init__(self, name, data, **kwargs): self.stop_processing = False self.prevent_default = False self.name = name self.data = data + self.params = SimpleNamespace(**kwargs) def dispatch(self, *args, **kwargs): for item in list(EVENT_CALLBACKS[self.name]): diff --git a/src/gamemodes.py b/src/gamemodes.py index 38eaeae..06040e8 100644 --- a/src/gamemodes.py +++ b/src/gamemodes.py @@ -1103,7 +1103,7 @@ class SleepyMode(GameMode): var.DYING.add(self.having_nightmare) 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 nickrole == "priest": pl = evt.data["pl"] diff --git a/src/roles/dullahan.py b/src/roles/dullahan.py new file mode 100644 index 0000000..e6c0b08 --- /dev/null +++ b/src/roles/dullahan.py @@ -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: diff --git a/src/roles/hunter.py b/src/roles/hunter.py index 9879e10..07ad308 100644 --- a/src/roles/hunter.py +++ b/src/roles/hunter.py @@ -23,6 +23,10 @@ def hunter_kill(cli, nick, chan, rest): 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"})) @@ -67,7 +71,7 @@ def hunter_pass(cli, nick, chan, rest): chk_nightdone(cli) @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()): if v == nick: HUNTERS.discard(h) diff --git a/src/roles/vigilante.py b/src/roles/vigilante.py index a633862..b5a16db 100644 --- a/src/roles/vigilante.py +++ b/src/roles/vigilante.py @@ -19,6 +19,10 @@ def vigilante_kill(cli, nick, chan, rest): 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"})) @@ -58,7 +62,7 @@ def vigilante_pass(cli, nick, chan, rest): chk_nightdone(cli) @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()): if v == nick: PASSED.discard(h) diff --git a/src/roles/wildchild.py b/src/roles/wildchild.py index 1cd127b..7970e02 100644 --- a/src/roles/wildchild.py +++ b/src/roles/wildchild.py @@ -73,7 +73,7 @@ def on_myrole(evt, cli, var, nick): evt.data["messages"].append(messages["wild_child_idol"].format(IDOLS[nick])) @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: 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["wolf"].add(child) 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) mass_privmsg(cli, wolves, messages["wild_child_as_wolf"].format(child)) if var.PHASE == "day": diff --git a/src/roles/wolf.py b/src/roles/wolf.py index 8c9c985..7497862 100644 --- a/src/roles/wolf.py +++ b/src/roles/wolf.py @@ -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) @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 n in b: if n == nick: diff --git a/src/wolfgame.py b/src/wolfgame.py index 92fae1e..7643749 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -2586,8 +2586,6 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True): iwon = False elif rol == "jester" and splr in var.JESTERS: 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"]: iwon = True 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))) del_player(cli, target, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False) 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 "DAY_TIME_LIMIT" not in var.ORIGINAL_SETTINGS: 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") pl = refresh_pl(pl) - event = Event("del_player", {"pl": pl}) - 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) + # i herd u liek parameters + 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): cmode.append(("-v", nick)) @@ -3573,7 +3543,7 @@ def rename_player(cli, prefix, nick): if prefix in dictvar.keys(): dictvar[nick] = dictvar.pop(prefix) # 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 = [] for a,b in dictvar.items(): nl = set() @@ -3826,7 +3796,7 @@ def begin_day(cli): # Reset nighttime variables 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.SEEN = set() # set of doomsayers that have had visions var.HEXED = set() # set of hags that have silenced others @@ -4685,11 +4655,6 @@ def chk_nightdone(cli): # don't count this twice 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: actedcount += len(var.MATCHMAKERS | var.CLONED.keys()) nightroles.extend(get_roles("matchmaker", "clone")) @@ -5328,15 +5293,11 @@ def kill(cli, nick, chan, rest): role = get_role(nick) except KeyError: role = None - if role != "dullahan" and nick not in var.VENGEFUL_GHOSTS.keys(): + 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 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: pm(cli, nick, messages["silenced"]) return @@ -5713,7 +5674,7 @@ def hvisit(cli, nick, chan, rest): var.HEXED.remove(victim) del var.LASTHEXED[victim] # 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"]: for s in var.ROLES["succubus"]: 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"]: pm(cli, victim, messages["no_kill_succubus"].format(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"]) + 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))) chk_nightdone(cli) @@ -6671,22 +6634,6 @@ def transition_night(cli): if role not in var.WOLFCHAT_ROLES: 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"]: pl = ps[:] random.shuffle(pl) @@ -7160,7 +7107,6 @@ def start(cli, nick, chan, forced = False, restart = ""): var.DYING = set() var.PRAYED = {} var.SICK = set() - var.DULLAHAN_TARGETS = {} var.DECEIVED = set() var.DEADCHAT_PLAYERS = set() @@ -7236,20 +7182,8 @@ def start(cli, nick, chan, forced = False, restart = ""): var.LAST_TIME = None var.LAST_VOTES = None - if var.ROLES["dullahan"]: # assign random targets to dullahan to kill - max_targets = math.ceil(8.1 * math.log(len(pl), 10) - 5) - 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) + event = Event("role_assignment", {}) + event.dispatch(cli, var, var.CURRENT_GAMEMODE.name, pl[:], restart) if not restart: gamemode = var.CURRENT_GAMEMODE.name @@ -7968,19 +7902,6 @@ def myrole(cli, nick, chan, rest): if role == "turncoat": 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 if nick not in var.ROLES["amnesiac"] and nick in var.GUNNERS and var.GUNNERS[nick]: role = "gunner" @@ -8433,12 +8354,6 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: elif role == "turncoat" and nickname in var.TURNCOATS: 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") - 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.dispatch(cli, var, nickname, role)