diff --git a/src/gamemodes.py b/src/gamemodes.py index 2bdd1fb..db866d9 100644 --- a/src/gamemodes.py +++ b/src/gamemodes.py @@ -4,6 +4,7 @@ import random import math import src.settings as var +import botconfig from src import events @@ -756,3 +757,67 @@ class SleepyMode(GameMode): self.TEMPLATE_RESTRICTIONS["prophet"] = frozenset(self.ROLE_GUIDE.keys()) - {"priest", "blessed villager", "prophet"} # this ensures that village drunk will always receive the gunner template self.TEMPLATE_RESTRICTIONS["gunner"] = frozenset(self.ROLE_GUIDE.keys()) - {"village drunk", "cursed villager", "gunner"} + # disable wolfchat + self.RESTRICT_WOLFCHAT = 0x0f + + self.having_nightmare = None + + def startup(self): + events.add_listener("dullahan_targets", self.dullahan_targets) + events.add_listener("transition_night_begin", self.setup_nightmare) + events.add_listener("chk_nightdone", self.prolong_night) + events.add_listener("transition_day_begin", self.nightmare_kill) + events.add_listener("del_player", self.happy_fun_times) + + def teardown(self): + events.remove_listener("dullahan_targets", self.dullahan_targets) + events.remove_listener("transition_night_begin", self.setup_nightmare) + events.remove_listener("chk_nightdone", self.prolong_night) + events.remove_listener("transition_day_begin", self.nightmare_kill) + events.remove_listener("del_player", self.happy_fun_times) + + def dullahan_targets(self, evt, cli, var, dullahans, max_targets): + for dull in dullahans: + evt.data["targets"][dull] = set(var.ROLES["priest"]) + + def setup_nightmares(self, evt, cli, var): + if random.random() < 1/5: + self.having_nightmare = random.choice(var.list_players()) + else: + self.having_nightmare = None + + def prolong_night(self, evt, cli, var): + if self.having_nightmare is not None: + evt.data["actedcount"] = -1 + + def nightmare_kill(self, evt, cli, var): + if self.having_nightmare is not None: + var.DYING.add(self.having_nightmare) + + def happy_fun_times(self, evt, cli, var, nick, nickrole, nicktpls, forced_death, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl): + if death_triggers: + if nickrole == "priest": + pl = evt.data["pl"] + seers = [p for p in var.list_players("seer") if p in pl] + harlots = [p for p in var.list_players("harlot") if p in pl] + cultists = [p for p in var.list_players("cultist") if p in pl] + total = sum(map(len, (seers, harlots, cultists))) + if total > 0: + cli.msg(botconfig.CHANNEL, ("The sky suddenly darkens as a thunderstorm appears from nowhere. The bell on the newly-abandoned church starts ringing " + + "in sinister tones, managing to perform \u0002{0}\u0002 tolls before the building is struck repeatedly by lightning, " + "setting it alight in a raging inferno...").format(total)) + for seer in seers: + var.ROLE["seer"].remove(seer) + var.ROLE["doomsayer"].add(seer) + # TODO: message + for harlot in harlots: + var.ROLE["harlot"].remove(harlot) + var.ROLE["succubus"].add(harlot) + # TODO: message + for cultist in cultists: + var.ROLE["cultist"].remove(cultist) + var.ROLE["demoniac"].add(cultist) + # TODO: message + # NOTE: chk_win is called by del_player, don't need to call it here even though this has a chance of ending game + +# vim: set expandtab:sw=4:ts=4: diff --git a/src/wolfgame.py b/src/wolfgame.py index ec55d31..54b1956 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -3174,6 +3174,10 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death cli.msg(botconfig.CHANNEL, tmsg) 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 ("night", "day"), killer_role, deadlist, original, ismain, refresh_pl) + if devoice and (var.PHASE != "night" or not var.DEVOICE_DURING_NIGHT): cmode.append(("-v", nick)) deadchat.append(nick) @@ -3719,6 +3723,9 @@ def rename_player(cli, prefix, nick): if prefix in var.ENTRANCED_DYING: var.ENTRANCED_DYING.remove(prefix) var.ENTRANCED_DYING.add(nick) + if prefix in var.DYING: + var.DYING.remove(prefix) + var.DYING.add(nick) if prefix in var.SICK: var.SICK.remove(prefix) var.SICK.add(nick) @@ -3944,6 +3951,7 @@ def begin_day(cli): var.MISDIRECTED = copy.copy(var.TOBEMISDIRECTED) var.ACTIVE_PROTECTIONS = defaultdict(list) var.ENTRANCED_DYING = set() + var.DYING = set() msg = ('The villagers must now vote for whom to lynch. '+ 'Use "{0}lynch " to cast your vote. {1} votes '+ @@ -4258,7 +4266,6 @@ def transition_day(cli, gameid=0): onlybywolves.discard(monster) wolfghostvictims = [] - dead_vigilantes = set() for k, d in var.OTHER_KILLS.items(): victims.append(d) onlybywolves.discard(d) @@ -4267,9 +4274,10 @@ def transition_day(cli, gameid=0): wolfghostvictims.append(d) if k in var.ROLES["vigilante"]: if var.get_role(d) not in var.WOLF_ROLES | {"monster", "succubus", "demoniac"}: - victims.append(k) - onlybywolves.discard(k) - dead_vigilantes.add(k) + var.DYING.add(k) + + for v in var.ENTRANCED_DYING: + var.DYING.add(v) # clear list so that it doesn't pm hunter / ghost about being able to kill again var.OTHER_KILLS = {} @@ -4279,7 +4287,7 @@ def transition_day(cli, gameid=0): onlybywolves.discard(d) killers[d].append(k) - for player in var.ENTRANCED_DYING: + for player in var.DYING: victims.append(player) onlybywolves.discard(player) @@ -4352,7 +4360,7 @@ def transition_day(cli, gameid=0): pl = var.list_players() for v in pl: if v in victims_set: - if v in var.ENTRANCED_DYING | dead_vigilantes: + if v in var.DYING: continue # bypass protections numkills = victims.count(v) numtotems = var.PROTECTED.count(v) @@ -4440,7 +4448,7 @@ def transition_day(cli, gameid=0): # can play. Harlot visiting wolf doesn't play special events if they die via other means since # that assumes they die en route to the wolves (and thus don't shoot/give out gun/etc.) for v in victims_set: - if v in var.ENTRANCED_DYING | dead_vigilantes: + if v in var.DYING: victims.append(v) elif v in var.ROLES["bodyguard"] and var.GUARDED.get(v) in victims_set: vappend.append(v) @@ -4867,31 +4875,32 @@ def chk_nightdone(cli): elif tu[1] < var.NIGHT_COUNT - 1: nightroles.append(tc) - event = Event("chk_nightdone", {}) + event = Event("chk_nightdone", {"actedcount": actedcount, "nightroles": nightroles}) event.dispatch(cli, var) if var.PHASE == "night" and actedcount >= len(nightroles): - # check for assassins that have not yet targeted - # must be handled separately because assassin only acts on nights when their target is dead - # and silenced assassin shouldn't add to actedcount - for ass in var.ROLES["assassin"]: - if ass not in var.TARGETED.keys() | var.SILENCED: - return - if not var.DISEASED_WOLVES: - # flatten var.KILLS - kills = set() - for ls in var.KILLS.values(): - if not isinstance(ls, str): - kills.update(ls) - else: - kills.add(ls) - # check if wolves are actually agreeing - # allow len(kills) == 0 through as that means that crow was dumb and observed instead - # of killingor alpha wolf was alone and chose to bite instead of kill - if not var.ANGRY_WOLVES and len(kills) > 1: - return - elif var.ANGRY_WOLVES and (len(kills) == 1 or len(kills) > 2): - return + if not event.prevent_default: + # check for assassins that have not yet targeted + # must be handled separately because assassin only acts on nights when their target is dead + # and silenced assassin shouldn't add to actedcount + for ass in var.ROLES["assassin"]: + if ass not in var.TARGETED.keys() | var.SILENCED: + return + if not var.DISEASED_WOLVES: + # flatten var.KILLS + kills = set() + for ls in var.KILLS.values(): + if not isinstance(ls, str): + kills.update(ls) + else: + kills.add(ls) + # check if wolves are actually agreeing + # allow len(kills) == 0 through as that means that crow was dumb and observed instead + # of killingor alpha wolf was alone and chose to bite instead of kill + if not var.ANGRY_WOLVES and len(kills) > 1: + return + elif var.ANGRY_WOLVES and (len(kills) == 1 or len(kills) > 2): + return for x, t in var.TIMERS.items(): t[0].cancel() @@ -7840,6 +7849,7 @@ def start(cli, nick, chan, forced = False, restart = ""): var.CONSECRATING = set() var.ENTRANCED = set() var.ENTRANCED_DYING = set() + var.DYING = set() var.PRAYED = {} var.SICK = set() var.DULLAHAN_TARGETS = {}