def observe(var, wrapper, message): """Observe a player to obtain various information.""" target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_observe_self") if not target: return if wrapper.source in OBSERVED: wrapper.pm(messages["already_observed"]) return if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["no_observe_wolf"]) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return OBSERVED.add(wrapper.source) targrole = get_main_role(target) if targrole == "amnesiac": from src.roles.amnesiac import ROLES as amn_roles targrole = amn_roles[target] an = "" key = "sorcerer_fail" if targrole in Spy: if targrole.startswith(("a", "e", "i", "o", "u")): an = "n" key = "sorcerer_success" wrapper.pm(messages[key].format(target, an, targrole)) send_wolfchat_message(var, wrapper.source, messages["sorcerer_success_wolfchat"].format(wrapper.source, target), {"sorcerer"}, role="sorcerer", command="observe") debuglog("{0} (sorcerer) OBSERVE: {1} ({2})".format(wrapper.source, target, targrole))
def vigilante_pass(var, wrapper, message): """Do not kill anyone tonight as a vigilante.""" del KILLS[:wrapper.source:] PASSED.add(wrapper.source) wrapper.send(messages["hunter_pass"]) debuglog("{0} (vigilante) PASS".format(wrapper.source))
def target(var, wrapper, message): """Pick a player as your target, killing them if you die.""" if wrapper.source in PREV_ACTED: wrapper.send(messages["assassin_already_targeted"]) return target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return evt = Event("targeted_command", { "target": target, "misdirection": True, "exchange": True }) if not evt.dispatch(var, wrapper.source, target): return target = evt.data["target"] TARGETED[wrapper.source] = target wrapper.send(messages["assassin_target_success"].format(target)) debuglog("{0} (assassin) TARGET: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def hunter_kill(var, wrapper, message): """Kill someone once per game.""" if wrapper.source in HUNTERS and wrapper.source not in KILLS: wrapper.pm(messages["hunter_already_killed"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide") if not target: return orig = target evt = Event("targeted_command", { "target": target, "misdirection": True, "exchange": True }) evt.dispatch(var, wrapper.source, target) if evt.prevent_default: return target = evt.data["target"] KILLS[wrapper.source] = target HUNTERS.add(wrapper.source) PASSED.discard(wrapper.source) wrapper.pm(messages["player_kill"].format(orig)) debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def vigilante_kill(var, wrapper, message): """Kill someone at night, but you die too if they aren't a wolf or win stealer!""" target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide") orig = target evt = Event("targeted_command", { "target": target, "misdirection": True, "exchange": True }) evt.dispatch(var, wrapper.source, target) if evt.prevent_default: return target = evt.data["target"] KILLS[wrapper.source] = target PASSED.discard(wrapper.source) wrapper.send(messages["player_kill"].format(orig)) debuglog("{0} (vigilante) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def immunize(var, wrapper, message): """Immunize a player, preventing them from turning into a wolf.""" if not DOCTORS[wrapper.source]: wrapper.pm(messages["doctor_fail"]) return target = get_target(var, wrapper, re.split(" +", message)[0], allow_self=True) if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return doctor_evt = Event("doctor_immunize", {"message": "villager_immunized"}) doctor_evt.dispatch(var, wrapper.source, target) wrapper.pm(messages["doctor_success"].format(target)) target.send(messages["immunization_success"].format(messages[doctor_evt.data["message"]])) IMMUNIZED.add(target) DOCTORS[wrapper.source] -= 1 remove_lycanthropy(var, target) remove_disease(var, target) debuglog("{0} (doctor) IMMUNIZE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def on_del_player(evt, var, player, all_roles, death_triggers): for h, v in list(KILLS.items()): if v is player: h.send(messages["hunter_discard"]) del KILLS[h] elif h is player: del KILLS[h] if death_triggers and "dullahan" in all_roles: pl = get_players() with TARGETS[player].intersection(pl) as targets: if targets: target = random.choice(list(targets)) protected = try_protection(var, target, player, "dullahan", "dullahan_die") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(target) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" channels.Main.send(messages["dullahan_die_success"].format(player, target, an, role)) else: channels.Main.send(messages["dullahan_die_success_noreveal"].format(player, target)) debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target))) add_dying(var, target, "dullahan", "dullahan_die")
def see(var, wrapper, message): """Use your paranormal senses to determine a player's doom.""" if wrapper.source in SEEN: wrapper.send(messages["seer_fail"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_see_self") if not target: return if is_known_wolf_ally(var, wrapper.source, target): wrapper.send(messages["no_see_wolf"]) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return targrole = get_main_role(target) mode, mapping = random.choice(_mappings) wrapper.send(messages["doomsayer_{0}".format(mode)].format(target)) mapping[wrapper.source] = target debuglog("{0} (doomsayer) SEE: {1} ({2}) - {3}".format(wrapper.source, target, targrole, mode.upper())) relay_wolfchat_command(wrapper.client, wrapper.source.nick, messages["doomsayer_wolfchat"].format(wrapper.source, target), ("doomsayer",), is_wolf_command=True) SEEN.add(wrapper.source)
def pass_cmd(var, wrapper, message): """Do not charm anyone tonight.""" del TOBECHARMED[:wrapper.source:] PASSED.add(wrapper.source) wrapper.send(messages["piper_pass"]) debuglog("{0} (piper) PASS".format(wrapper.source))
def consecrate(var, wrapper, message): """Consecrates a corpse, putting its spirit to rest and preventing other unpleasant things from happening.""" alive = get_players() targ = re.split(" +", message)[0] if not targ: wrapper.pm(messages["not_enough_parameters"]) return dead = set(var.ALL_PLAYERS) - set(alive) target, _ = users.complete_match(targ, dead) if target is None: wrapper.pm(messages["consecrate_fail"].format(targ)) return # we have a target, so mark them as consecrated, right now all this does is silence a VG for a night # 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 evt = Event("consecrate", {}) evt.dispatch(var, wrapper.source, target) wrapper.pm(messages["consecrate_success"].format(target)) debuglog("{0} (priest) CONSECRATE: {1}".format(wrapper.source, target)) add_absent(var, wrapper.source, "consecrating") from src.votes import chk_decision from src.wolfgame import chk_win if not chk_win(): # game didn't immediately end due to marking as absent, see if we should force through a lynch chk_decision(var)
def see(cli, nick, chan, rest): """Use your paranormal senses to determine a player's doom.""" role = get_role(nick) if nick in SEEN: pm(cli, nick, messages["seer_fail"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if victim == nick: pm(cli, nick, messages["no_see_self"]) return if in_wolflist(nick, victim): pm(cli, nick, messages["no_see_wolf"]) return evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": True}) evt.dispatch(cli, var, "see", nick, victim, frozenset({"detrimental", "immediate"})) if evt.prevent_default: return victim = evt.data["target"] victimrole = get_role(victim) mode, mapping = random.choice(_mappings) pm(cli, nick, messages["doomsayer_{0}".format(mode)].format(victim)) if mode != "sick" or nick not in var.IMMUNIZED: mapping[nick] = victim debuglog("{0} ({1}) SEE: {2} ({3}) - {4}".format(nick, role, victim, victimrole, mode.upper())) relay_wolfchat_command(cli, nick, messages["doomsayer_wolfchat"].format(nick, victim), ("doomsayer",), is_wolf_command=True) SEEN.add(nick) chk_nightdone(cli)
def observe(var, wrapper, message): """Observe a player to see whether they are able to act at night.""" if wrapper.source in OBSERVED: wrapper.pm(messages["werecrow_already_observing"].format( OBSERVED[wrapper.source])) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="werecrow_no_observe_self") if not target: return if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["werecrow_no_target_wolf"]) return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return OBSERVED[wrapper.source] = target wrapper.pm(messages["werecrow_observe_success"].format(orig)) send_wolfchat_message(var, wrapper.source, messages["wolfchat_observe"].format( wrapper.source, target), {"werecrow"}, role="werecrow", command="observe") debuglog("{0} (werecrow) OBSERVE: {1} ({2})".format( wrapper.source, target, get_main_role(target)))
def on_transition_day_resolve_end(evt, var, victims): evt2 = Event("get_role_metadata", {}) evt2.dispatch(var, "lycanthropy_role") for victim in victims: if victim in LYCANTHROPES and evt.data["killers"][victim] == ["@wolves"] and victim in evt.data["dead"]: vrole = get_main_role(victim) if vrole not in Wolf: new_role = "wolf" prefix = LYCANTHROPES[victim] if vrole in evt2.data: if "role" in evt2.data[vrole]: new_role = evt2.data[vrole]["role"] if "prefix" in evt2.data[vrole]: prefix = evt2.data[vrole]["prefix"] for sec_role in evt2.data[vrole].get("secondary_roles", ()): var.ROLES[sec_role].add(victim) to_send = "{0}_{1}".format(sec_role.replace(" ", "_"), "simple" if victim.prefers_simple() else "notify") victim.send(messages[to_send]) # FIXME: Not every role has proper message keys, such as shamans change_role(var, victim, vrole, new_role, message=prefix + "_turn") evt.data["howl"] += 1 evt.data["novictmsg"] = False evt.data["dead"].remove(victim) evt.data["killers"][victim].remove("@wolves") del evt.data["message"][victim] debuglog("{0} ({1}) TURN {2}".format(victim, vrole, new_role))
def hex_cmd(var, wrapper, message): """Hex someone, preventing them from acting the next day and night.""" if wrapper.source in HEXED: wrapper.pm(messages["already_hexed"]) return target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if LASTHEXED.get(wrapper.source) is target: wrapper.pm(messages["no_multiple_hex"].format(target)) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["no_hex_wolf"]) return HEXED[wrapper.source] = target wrapper.pm(messages["hex_success"].format(target)) send_wolfchat_message(var, wrapper.source, messages["hex_success_wolfchat"].format(wrapper.source, target), {"hag"}, role="hag", command="hex") debuglog("{0} (hag) HEX: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def guard(var, wrapper, message): """Guard a player, preventing them from being killed that night.""" if wrapper.source in GUARDED: wrapper.pm(messages["already_protecting"]) return target = get_target(var, wrapper, re.split(" +", message)[0], allow_self=var.GUARDIAN_ANGEL_CAN_GUARD_SELF, not_self_message="cannot_guard_self") if not target: return if LASTGUARDED.get(wrapper.source) is target: wrapper.pm(messages["guardian_target_another"].format(target)) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return add_protection(var, target, wrapper.source, "guardian angel") GUARDED[wrapper.source] = target LASTGUARDED[wrapper.source] = target if wrapper.source is target: wrapper.pm(messages["guardian_guard_self"]) else: wrapper.pm(messages["protecting_target"].format(target)) target.send(messages["target_protected"]) debuglog("{0} (guardian angel) GUARD: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def on_del_player(evt, var, player, all_roles, death_triggers): for h, v in list(KILLS.items()): if v is player: h.send(messages["hunter_discard"]) del KILLS[h] elif h is player: del KILLS[h] if death_triggers and "dullahan" in all_roles: pl = get_players() with TARGETS[player].intersection(pl) as targets: if targets: target = random.choice(list(targets)) protected = try_protection(var, target, player, "dullahan", "dullahan_die") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(target) channels.Main.send(messages["dullahan_die_success"].format( player, target, role)) else: channels.Main.send( messages["dullahan_die_success_noreveal"].format( player, target)) debuglog( "{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format( player, target, get_main_role(target))) add_dying(var, target, "dullahan", "dullahan_die")
def hvisit(var, wrapper, message): """Visit a player. You will die if you visit a wolf or a target of the wolves.""" if VISITED.get(wrapper.source): wrapper.pm(messages["harlot_already_visited"].format(VISITED[wrapper.source])) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="harlot_not_self") if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return vrole = get_main_role(target) VISITED[wrapper.source] = target PASSED.discard(wrapper.source) wrapper.pm(messages["harlot_success"].format(target)) if target is not wrapper.source: target.send(messages["harlot_success"].format(wrapper.source)) revt = Event("harlot_visit", {}) revt.dispatch(var, wrapper.source, target) debuglog("{0} (harlot) VISIT: {1} ({2})".format(wrapper.source, target, vrole))
def vigilante_kill(cli, nick, chan, rest): """Kill someone at night, but you die too if they aren't a wolf or win stealer!""" 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 PASSED.discard(nick) 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)
def dullahan_kill(var, wrapper, message): """Kill someone at night as a dullahan until everyone on your list is dead.""" if not TARGETS[wrapper.source] & set(get_players()): wrapper.pm(messages["dullahan_targets_dead"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide") if not target: return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return target = evt.data["target"] KILLS[wrapper.source] = target wrapper.pm(messages["player_kill"].format(orig)) debuglog("{0} (dullahan) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def hunter_kill(cli, nick, chan, rest): """Kill someone once per game.""" if nick in HUNTERS and nick not in KILLS: pm(cli, nick, messages["hunter_already_killed"]) 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 HUNTERS.add(nick) PASSED.discard(nick) 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)
def clone(var, wrapper, message): """Clone another player. You will turn into their role if they die.""" if not var.FIRST_NIGHT: return if wrapper.source in CLONED: wrapper.pm(messages["already_cloned"]) return params = re.split(" +", message) # allow for role-prefixed command such as !clone clone target # if we get !clone clone (with no 3rd arg), we give preference to prefixed version; # meaning if the person wants to clone someone named clone, they must type !clone clone clone # (or just !clone clon, !clone clo, etc. assuming those would be unambiguous matches) if params[0] == "clone": if len(params) > 1: del params[0] else: wrapper.pm(messages["clone_clone_clone"]) return target = get_target(var, wrapper, params[0]) if target is None: return CLONED[wrapper.source] = target wrapper.pm(messages["clone_target_success"].format(target)) debuglog("{0} (clone) CLONE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def see(var, wrapper, message): """Use your paranormal powers to determine the role or alignment of a player.""" if wrapper.source in SEEN: wrapper.send(messages["seer_fail"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_see_self") if target is None: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return targrole = get_main_role(target) trole = targrole # keep a copy for logging evt = Event("investigate", {"role": targrole}) evt.dispatch(var, wrapper.source, target) targrole = evt.data["role"] aura = "blue" if targrole in Wolfteam: aura = "red" elif targrole in Neutral: aura = "grey" wrapper.send(messages["augur_success"].format(target, aura)) debuglog("{0} (augur) SEE: {1} ({2}) as {3} ({4} aura)".format(wrapper.source, target, trole, targrole, aura)) SEEN.add(wrapper.source)
def vg_kill(var, wrapper, message): """Take revenge on someone each night after you die.""" if GHOSTS[wrapper.source][0] == "!": return target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if target is wrapper.source: wrapper.pm(messages["player_dead"]) return wolves = get_players(Wolfteam) if GHOSTS[wrapper.source] == "wolves" and target not in wolves: wrapper.pm(messages["vengeful_ghost_wolf"]) return elif GHOSTS[wrapper.source] == "villagers" and target in wolves: wrapper.pm(messages["vengeful_ghost_villager"]) return orig = target target = try_misdirection(var, wrapper.source, target) KILLS[wrapper.source] = target wrapper.pm(messages["player_kill"].format(orig)) debuglog("{0} (vengeful ghost) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def choose(var, wrapper, message): """Select two players to fall in love. You may select yourself as one of the lovers.""" if wrapper.source in MATCHMAKERS: wrapper.send(messages["already_matched"]) return pieces = re.split(" +", message) victim1 = pieces[0] if len(pieces) > 1: if len(pieces) > 2 and pieces[1].lower() == "and": victim2 = pieces[2] else: victim2 = pieces[1] else: victim2 = None target1 = get_target(var, wrapper, victim1, allow_self=True) target2 = get_target(var, wrapper, victim2, allow_self=True) if not target1 or not target2: return if target1 is target2: wrapper.send(messages["match_different_people"]) return MATCHMAKERS.add(wrapper.source) _set_lovers(target1, target2) wrapper.send(messages["matchmaker_success"].format(target1, target2)) debuglog("{0} (matchmaker) MATCH: {1} ({2}) WITH {3} ({4})".format( wrapper.source, target1, get_main_role(target1), target2, get_main_role(target2)))
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)
def hvisit(cli, nick, chan, rest): """Visit a player. You will die if you visit a wolf or a target of the wolves.""" if VISITED.get(nick): pm(cli, nick, messages["harlot_already_visited"].format(VISITED[nick])) return victim = get_victim(cli, nick, re.split(" +", rest)[0], False, True) if not victim: return if nick == victim: pm(cli, nick, messages["harlot_not_self"]) return evt = Event("targeted_command", { "target": victim, "misdirection": True, "exchange": True }) evt.dispatch(cli, var, "visit", nick, victim, frozenset({"immediate"})) if evt.prevent_default: return victim = evt.data["target"] vrole = get_role(victim) VISITED[nick] = victim pm(cli, nick, messages["harlot_success"].format(victim)) if nick != victim: pm(cli, victim, messages["harlot_success"].format(nick)) revt = Event("harlot_visit", {}) revt.dispatch(cli, var, nick, victim) debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, get_role(nick), victim, vrole)) chk_nightdone(cli)
def dullahan_kill(var, wrapper, message): """Kill someone at night as a dullahan until everyone on your list is dead.""" if not TARGETS[wrapper.source] & set(get_players()): wrapper.pm(messages["dullahan_targets_dead"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide") if not target: return orig = target evt = Event("targeted_command", { "target": target, "misdirection": True, "exchange": True }) evt.dispatch(var, "kill", wrapper.source, target, frozenset({"detrimental"})) if evt.prevent_default: return target = evt.data["target"] KILLS[wrapper.source] = target wrapper.pm(messages["player_kill"].format(orig)) debuglog("{0} (dullahan) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def on_chk_win(evt, var, rolemap, mainroles, lpl, lwolves, lrealwolves): did_something = False if lrealwolves == 0: for traitor in list(rolemap["traitor"]): rolemap["wolf"].add(traitor) rolemap["traitor"].remove(traitor) rolemap["cursed villager"].discard(traitor) mainroles[traitor] = "wolf" did_something = True if var.PHASE in var.GAME_PHASES: var.FINAL_ROLES[traitor.nick] = "wolf" # FIXME traitor.send(messages["traitor_turn"]) debuglog(traitor, "(traitor) TURNING") if did_something: if var.PHASE in var.GAME_PHASES: var.TRAITOR_TURNED = True channels.Main.send(messages["traitor_turn_channel"]) # fix !stats to show that traitor turned as well newstats = set() for rs in var.ROLE_STATS: d = dict(rs) # traitor count of 0 is not possible since we for-sure turned traitors into wolves earlier # as such, exclude such cases from newstats entirely. if d["traitor"] >= 1: d["wolf"] += d["traitor"] d["traitor"] = 0 newstats.add(frozenset(d.items())) var.ROLE_STATS = frozenset(newstats) evt.prevent_default = True evt.stop_processing = True
def guard(var, wrapper, message): """Guard a player, preventing them from being killed that night.""" if wrapper.source in GUARDED: wrapper.pm(messages["already_protecting"]) return target = get_target(var, wrapper, re.split(" +", message)[0], allow_self=var.GUARDIAN_ANGEL_CAN_GUARD_SELF, not_self_message="cannot_guard_self") if not target: return if LASTGUARDED.get(wrapper.source) is target: wrapper.pm(messages["guardian_target_another"].format(target)) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return add_protection(var, target, wrapper.source, "guardian angel") GUARDED[wrapper.source] = target LASTGUARDED[wrapper.source] = target if wrapper.source is target: wrapper.pm(messages["guardian_guard_self"]) else: wrapper.pm(messages["protecting_target"].format(target)) target.send(messages["target_protected"]) debuglog("{0} (guardian angel) GUARD: {1} ({2})".format( wrapper.source, target, get_main_role(target)))
def retract(var, wrapper, message): """Retract your bite.""" if wrapper.source in BITTEN: del BITTEN[wrapper.source] wrapper.pm(messages["no_bite"]) send_wolfchat_message(var, wrapper.source, messages["wolfchat_no_bite"].format(wrapper.source), {"alpha wolf"}, role="alpha wolf", command="retract") debuglog("{0} (alpha wolf) RETRACT BITE".format(wrapper.source))
def guard(cli, nick, chan, rest): """Guard a player, preventing them from being killed that night.""" if nick in GUARDED: pm(cli, nick, messages["already_protecting"]) return role = get_role(nick) self_in_list = role == "guardian angel" and var.GUARDIAN_ANGEL_CAN_GUARD_SELF victim = get_victim(cli, nick, re.split(" +",rest)[0], False, self_in_list) if not victim: return if (role == "bodyguard" or not var.GUARDIAN_ANGEL_CAN_GUARD_SELF) and victim == nick: pm(cli, nick, messages["cannot_guard_self"]) return if role == "guardian angel" and LASTGUARDED.get(nick) == victim: pm(cli, nick, messages["guardian_target_another"].format(victim)) return # self-guard ignores luck/misdirection/exchange totem evt = Event("targeted_command", {"target": victim, "misdirection": victim != nick, "exchange": victim != nick}) if not evt.dispatch(cli, var, "guard", nick, victim, frozenset({"beneficial"})): return victim = evt.data["target"] GUARDED[nick] = victim LASTGUARDED[nick] = victim if victim == nick: pm(cli, nick, messages["guardian_guard_self"]) else: pm(cli, nick, messages["protecting_target"].format(GUARDED[nick])) pm(cli, victim, messages["target_protected"]) debuglog("{0} ({1}) GUARD: {2} ({3})".format(nick, role, victim, get_role(victim))) chk_nightdone(cli)
def curse(var, wrapper, message): target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if target in get_all_players(("cursed villager",)): wrapper.pm(messages["target_already_cursed"].format(target)) return # There may actually be valid strategy in cursing other wolfteam members, # but for now it is not allowed. If someone seems suspicious and shows as # villager across multiple nights, safes can use that as a tell that the # person is likely wolf-aligned. if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["no_curse_wolf"]) return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return CURSED[wrapper.source] = target PASSED.discard(wrapper.source) wrapper.pm(messages["curse_success"].format(orig)) send_wolfchat_message(var, wrapper.source, messages["curse_success_wolfchat"].format(wrapper.source, orig), {"warlock"}, role="warlock", command="curse") debuglog("{0} (warlock) CURSE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
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)
def hunter_kill(var, wrapper, message): """Kill someone once per game.""" if wrapper.source in HUNTERS and wrapper.source not in KILLS: wrapper.pm(messages["hunter_already_killed"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide") if not target: return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return KILLS[wrapper.source] = target HUNTERS.add(wrapper.source) PASSED.discard(wrapper.source) wrapper.pm(messages["player_kill"].format(orig)) debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def hex_cmd(var, wrapper, message): """Hex someone, preventing them from acting the next day and night.""" if wrapper.source in HEXED: wrapper.pm(messages["already_hexed"]) return target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if LASTHEXED.get(wrapper.source) is target: wrapper.pm(messages["no_multiple_hex"].format(target)) return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["no_hex_wolf"]) return HEXED[wrapper.source] = target wrapper.pm(messages["hex_success"].format(target)) send_wolfchat_message(var, wrapper.source, messages["hex_success_wolfchat"].format( wrapper.source, target), {"hag"}, role="hag", command="hex") debuglog("{0} (hag) HEX: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def vg_kill(cli, nick, chan, rest): """Take revenge on someone each night after you die.""" if GHOSTS[nick][0] == "!": 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)
def hunter_kill(cli, nick, chan, rest): """Kill someone once per game.""" if nick in HUNTERS and nick not in KILLS: pm(cli, nick, messages["hunter_already_killed"]) 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 HUNTERS.add(nick) PASSED.discard(nick) 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)
def choose(var, wrapper, message): """Select two players to fall in love. You may select yourself as one of the lovers.""" if wrapper.source in MATCHMAKERS: wrapper.send(messages["already_matched"]) return pieces = re.split(" +", message) victim1 = pieces[0] if len(pieces) > 1: if len(pieces) > 2 and pieces[1].lower() == "and": victim2 = pieces[2] else: victim2 = pieces[1] else: victim2 = None target1 = get_target(var, wrapper, victim1, allow_self=True) target2 = get_target(var, wrapper, victim2, allow_self=True) if not target1 or not target2: return if target1 is target2: wrapper.send(messages["match_different_people"]) return MATCHMAKERS.add(wrapper.source) _set_lovers(target1, target2) wrapper.send(messages["matchmaker_success"].format(target1, target2)) debuglog("{0} (matchmaker) MATCH: {1} ({2}) WITH {3} ({4})".format(wrapper.source, target1, get_main_role(target1), target2, get_main_role(target2)))
def hvisit(var, wrapper, message): """Entrance a player, converting them to your team.""" if VISITED.get(wrapper.source): wrapper.send(messages["succubus_already_visited"].format(VISITED[wrapper.source])) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="succubus_not_self") if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return VISITED[wrapper.source] = target PASSED.discard(wrapper.source) if target not in get_all_players(("succubus",)): ENTRANCED.add(target) wrapper.send(messages["succubus_target_success"].format(target)) else: wrapper.send(messages["harlot_success"].format(target)) if wrapper.source is not target: if target not in get_all_players(("succubus",)): target.send(messages["notify_succubus_target"].format(wrapper.source)) else: target.send(messages["harlot_success"].format(wrapper.source)) revt = Event("succubus_visit", {}) revt.dispatch(var, wrapper.source, target) debuglog("{0} (succubus) VISIT: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def curse(var, wrapper, message): target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if target in get_all_players(("cursed villager", )): wrapper.pm(messages["target_already_cursed"].format(target)) return # There may actually be valid strategy in cursing other wolfteam members, # but for now it is not allowed. If someone seems suspicious and shows as # villager across multiple nights, safes can use that as a tell that the # person is likely wolf-aligned. if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["no_curse_wolf"]) return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return CURSED[wrapper.source] = target PASSED.discard(wrapper.source) wrapper.pm(messages["curse_success"].format(orig)) send_wolfchat_message(var, wrapper.source, messages["curse_success_wolfchat"].format( wrapper.source, orig), {"warlock"}, role="warlock", command="curse") debuglog("{0} (warlock) CURSE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def hvisit(var, wrapper, message): """Entrance a player, converting them to your team.""" if VISITED.get(wrapper.source): wrapper.send(messages["succubus_already_visited"].format(VISITED[wrapper.source])) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="succubus_not_self") if not target: return evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True}) if not evt.dispatch(var, wrapper.source, target): return target = evt.data["target"] VISITED[wrapper.source] = target PASSED.discard(wrapper.source) if target not in get_all_players(("succubus",)): ENTRANCED.add(target) wrapper.send(messages["succubus_target_success"].format(target)) else: wrapper.send(messages["harlot_success"].format(target)) if wrapper.source is not target: if target not in get_all_players(("succubus",)): target.send(messages["notify_succubus_target"].format(wrapper.source)) else: target.send(messages["harlot_success"].format(wrapper.source)) revt = Event("succubus_visit", {}) revt.dispatch(var, wrapper.source, target) debuglog("{0} (succubus) VISIT: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def observe(var, wrapper, message): """Turn a player into a wolf!""" if not ENABLED: wrapper.pm(messages["alpha_no_bite"]) return if wrapper.source in ALPHAS: wrapper.pm(messages["alpha_already_bit"]) return target = get_target(var, wrapper, re.split(" +", message)[0]) if not target: return if is_known_wolf_ally(var, wrapper.source, target): wrapper.pm(messages["alpha_no_bite_wolf"]) return orig = target target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return BITTEN[wrapper.source] = target wrapper.pm(messages["alpha_bite_target"].format(orig)) send_wolfchat_message(var, wrapper.source, messages["alpha_bite_wolfchat"].format( wrapper.source, target), {"alpha wolf"}, role="alpha wolf", command="bite") debuglog("{0} (alpha wolf) BITE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
def vigilante_pass(var, wrapper, message): """Do not kill anyone tonight as a vigilante.""" KILLS.pop(wrapper.source, None) PASSED.add(wrapper.source) wrapper.send(messages["hunter_pass"]) debuglog("{0} (vigilante) PASS".format(wrapper.source))
def hvisit(var, wrapper, message): """Visit a player. You will die if you visit a wolf or a target of the wolves.""" if VISITED.get(wrapper.source): wrapper.pm(messages["harlot_already_visited"].format( VISITED[wrapper.source])) return if wrapper.source in FORCE_PASSED: wrapper.pm(messages["already_being_visited"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="harlot_not_self") if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return vrole = get_main_role(target) VISITED[wrapper.source] = target PASSED.discard(wrapper.source) wrapper.pm(messages["harlot_success"].format(target)) if target is not wrapper.source: target.send(messages["harlot_success"].format(wrapper.source)) revt = Event("visit", {}) revt.dispatch(var, "harlot", wrapper.source, target) debuglog("{0} (harlot) VISIT: {1} ({2})".format(wrapper.source, target, vrole))
def retract(var, wrapper, message): """Remove your decision to charm people.""" if wrapper.source in TOBECHARMED or wrapper.source in PASSED: del TOBECHARMED[:wrapper.source:] PASSED.discard(wrapper.source) wrapper.send(messages["piper_retract"]) debuglog("{0} (piper) RETRACT".format(wrapper.source))
def pass_cmd(var, wrapper, message): """Do not visit someone tonight.""" if VISITED.get(wrapper.source): wrapper.pm(messages["harlot_already_visited"].format(VISITED[wrapper.source])) return PASSED.add(wrapper.source) wrapper.pm(messages["no_visit"]) debuglog("{0} (harlot) PASS".format(wrapper.source))
def pass_cmd(var, wrapper, message): """Decline to use your special power for that night.""" if wrapper.source in GUARDED: wrapper.pm(messages["already_protecting"]) return PASSED.add(wrapper.source) wrapper.pm(messages["guardian_no_protect"]) debuglog("{0} (bodyguard) PASS".format(wrapper.source))
def pass_cmd(var, wrapper, message): """Do not entrance someone tonight.""" if VISITED.get(wrapper.source): wrapper.send(messages["succubus_already_visited"].format(VISITED[wrapper.source])) return PASSED.add(wrapper.source) wrapper.send(messages["succubus_pass"]) debuglog("{0} (succubus) PASS".format(wrapper.source))
def vigilante_pass(cli, nick, chan, rest): """Do not kill anyone tonight as a vigilante.""" if nick in KILLS: del KILLS[nick] PASSED.add(nick) pm(cli, nick, messages["hunter_pass"]) debuglog("{0} ({1}) PASS".format(nick, get_role(nick))) chk_nightdone(cli)
def pass_cmd(var, wrapper, message): """Decline to use your special power for that night.""" del CURSED[:wrapper.source:] PASSED.add(wrapper.source) wrapper.pm(messages["warlock_pass"]) send_wolfchat_message(var, wrapper.source, messages["warlock_pass_wolfchat"].format(wrapper.source), {"warlock"}, role="warlock", command="pass") debuglog("{0} (warlock) PASS".format(wrapper.source))
def retract(var, wrapper, message): """Retract your curse or pass.""" del CURSED[:wrapper.source:] PASSED.discard(wrapper.source) wrapper.pm(messages["warlock_retract"]) send_wolfchat_message(var, wrapper.source, messages["warlock_retract_wolfchat"].format(wrapper.source), {"warlock"}, role="warlock", command="retract") debuglog("{0} (warlock) RETRACT".format(wrapper.source))
def vigilante_retract(var, wrapper, message): """Removes a vigilante's kill selection.""" if wrapper.source not in KILLS and wrapper.source not in PASSED: return del KILLS[:wrapper.source:] PASSED.discard(wrapper.source) wrapper.send(messages["retracted_kill"]) debuglog("{0} (vigilante) RETRACT".format(wrapper.source))
def on_transition_night_begin(evt, var): global STATS_FLAG if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS: amnesiacs = get_all_players(("amnesiac",)) if amnesiacs and not var.HIDDEN_AMNESIAC: STATS_FLAG = True for amn in amnesiacs: role = change_role(var, amn, "amnesiac", ROLES[amn], message="amnesia_clear") debuglog("{0} REMEMBER: {1}".format(amn, role))
def pm(cli, target, message): if is_fake_nick(target) and botconfig.DEBUG_MODE: debuglog("Would message fake nick {0}: {1!r}".format(target, message)) return if is_user_notice(target): cli.notice(target, message) return cli.msg(target, message)