Beispiel #1
0
    def startup(self):
        super().startup()
        self.having_nightmare = UserList()

        cmd_params = dict(chan=False,
                          pm=True,
                          playing=True,
                          phases=("night", ),
                          users=self.having_nightmare)

        self.north_cmd = command("north", "n", **cmd_params)(functools.partial(
            self.move, "n"))
        self.east_cmd = command("east", "e", **cmd_params)(functools.partial(
            self.move, "e"))
        self.south_cmd = command("south", "s", **cmd_params)(functools.partial(
            self.move, "s"))
        self.west_cmd = command("west", "w", **cmd_params)(functools.partial(
            self.move, "w"))
Beispiel #2
0
def wolf_kill(var, wrapper, message):
    """Kills one or more players as a wolf."""
    role = get_main_role(wrapper.source)
    # eventually cub will listen on targeted_command and block kills that way
    if var.DISEASED_WOLVES:
        wrapper.pm(messages["ill_wolves"])
        return

    pieces = re.split(" +", message)
    targets = []
    orig = []

    nevt = Event("wolf_numkills", {"numkills": 1})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]

    if len(pieces) < num_kills:
        wrapper.pm(messages["wolf_must_target_multiple"])
        return

    targs = iter(pieces) # allow random words to follow the initial line without issue
    for i in range(num_kills):
        target = get_target(var, wrapper, next(targs, None), not_self_message="no_suicide")
        if target is None:
            return

        if is_known_wolf_ally(var, wrapper.source, target):
            wrapper.pm(messages["wolf_no_target_wolf"])
            return

        if target in orig:
            wrapper.pm(messages["wolf_must_target_multiple"])
            return

        orig.append(target)

        evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
        if not evt.dispatch(var, wrapper.source, target):
            return

        target = evt.data["target"]
        targets.append(target)

    KILLS[wrapper.source] = UserList(targets)

    if len(orig) > 1:
        # TODO: Expand this so we can support arbitrarily many kills (instead of just one or two)
        wrapper.pm(messages["player_kill_multiple"].format(*orig))
        msg = messages["wolfchat_kill_multiple"].format(wrapper.source, *orig)
        debuglog("{0} ({1}) KILL: {2} ({4}) and {3} ({5})".format(wrapper.source, role, *targets, get_main_role(targets[0]), get_main_role(targets[1])))
    else:
        wrapper.pm(messages["player_kill"].format(orig[0]))
        msg = messages["wolfchat_kill"].format(wrapper.source, orig[0])
        debuglog("{0} ({1}) KILL: {2} ({3})".format(wrapper.source, role, targets[0], get_main_role(targets[0])))

    send_wolfchat_message(var, wrapper.source, msg, var.WOLF_ROLES, role=role, command="kill")
Beispiel #3
0
def wolf_kill(var, wrapper, message):
    """Kill one or more players as a wolf."""
    # verify this user can actually kill
    if not get_all_roles(wrapper.source) & Wolf & Killer:
        return

    pieces = re.split(" +", message)
    targets = []
    orig = []

    nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]

    if not num_kills:
        if nevt.data["message"]:
            wrapper.pm(messages[nevt.data["message"]])
        return

    if len(pieces) < num_kills:
        wrapper.pm(messages["wolf_must_target_multiple"])
        return

    for targ in pieces[:num_kills]:
        target = get_target(var, wrapper, targ, not_self_message="no_suicide")
        if target is None:
            return

        if is_known_wolf_ally(var, wrapper.source, target):
            wrapper.pm(messages["wolf_no_target_wolf"])
            return

        if target in orig:
            wrapper.pm(messages["wolf_must_target_multiple"])
            return

        orig.append(target)
        target = try_misdirection(var, wrapper.source, target)
        if try_exchange(var, wrapper.source, target):
            return

        targets.append(target)

    KILLS[wrapper.source] = UserList(targets)

    if len(orig) > 1:
        wrapper.pm(messages["player_kill_multiple"].format(orig))
        msg = messages["wolfchat_kill_multiple"].format(wrapper.source, orig)
        debuglog("{0} KILL: {1} ({3}) and {2} ({4})".format(wrapper.source, targets[0], targets[1], get_main_role(targets[0]), get_main_role(targets[1])))
    else:
        wrapper.pm(messages["player_kill"].format(orig[0]))
        msg = messages["wolfchat_kill"].format(wrapper.source, orig[0])
        debuglog("{0} KILL: {1} ({2})".format(wrapper.source, targets[0], get_main_role(targets[0])))

    send_wolfchat_message(var, wrapper.source, msg, Wolf, role="wolf", command="kill")
Beispiel #4
0
    def on_transition_day_begin2(evt, var):
        LASTGIVEN.clear()
        for shaman, given in SHAMANS.items():
            for totem, targets in given.items():
                for target in targets:
                    victim = RETARGET[shaman].get(target, target)
                    if not victim:
                        continue
                    if totem == "death":  # this totem stacks
                        if shaman not in DEATH:
                            DEATH[shaman] = UserList()
                        DEATH[shaman].append(victim)
                    elif totem == "protection":  # this totem stacks
                        PROTECTION.append(victim)
                    elif totem == "revealing":
                        REVEALING.add(victim)
                    elif totem == "narcolepsy":
                        NARCOLEPSY.add(victim)
                    elif totem == "silence":
                        SILENCE.add(victim)
                    elif totem == "desperation":
                        DESPERATION.add(victim)
                    elif totem == "impatience":  # this totem stacks
                        IMPATIENCE.append(victim)
                    elif totem == "pacifism":  # this totem stacks
                        PACIFISM.append(victim)
                    elif totem == "influence":
                        INFLUENCE.add(victim)
                    elif totem == "exchange":
                        EXCHANGE.add(victim)
                    elif totem == "lycanthropy":
                        LYCANTHROPY.add(victim)
                    elif totem == "luck":
                        LUCK.add(victim)
                    elif totem == "pestilence":
                        PESTILENCE.add(victim)
                    elif totem == "retribution":
                        RETRIBUTION.add(victim)
                    elif totem == "misdirection":
                        MISDIRECTION.add(victim)
                    elif totem == "deceit":
                        DECEIT.add(victim)
                    else:
                        event = Event("apply_totem", {})
                        event.dispatch(var, rolename, totem, shaman, victim)

                    if target is not victim:
                        shaman.send(messages["totem_retarget"].format(
                            victim, target))
                    LASTGIVEN[shaman][totem].append(victim)
                    havetotem.append(victim)
Beispiel #5
0
def give_totem(var, wrapper, target, prefix, role, msg):
    """Give a totem to a player. Return the value of SHAMANS[user]."""

    orig_target = target
    orig_role = get_main_role(orig_target)

    target = try_misdirection(var, wrapper.source, target)
    if try_exchange(var, wrapper.source, target):
        return

    targrole = get_main_role(target)

    wrapper.send(messages["shaman_success"].format(prefix, msg, orig_target))
    debuglog("{0} ({1}) TOTEM: {2} ({3}) as {4} ({5})".format(
        wrapper.source, role, target, targrole, orig_target, orig_role))

    return UserList((target, orig_target))
Beispiel #6
0
def lynch(var, wrapper, message):
    """Use this to vote for a candidate to be lynched."""
    if not message:
        show_votes.func(var, wrapper, message)
        return
    if wrapper.private:
        return
    msg = re.split(" +", message)[0].strip()

    can_vote_bot = var.CURRENT_GAMEMODE.can_vote_bot(var)

    voted = get_target(var,
                       wrapper,
                       msg,
                       allow_self=var.SELF_LYNCH_ALLOWED,
                       allow_bot=can_vote_bot,
                       not_self_message="no_self_lynch")
    if not voted:
        return

    if try_absent(var, wrapper.source):
        return

    ABSTAINS.discard(wrapper.source)

    for votee in list(VOTES):  # remove previous vote
        if votee is voted and wrapper.source in VOTES[votee]:
            break
        if wrapper.source in VOTES[votee]:
            VOTES[votee].remove(wrapper.source)
            if not VOTES.get(votee) and votee is not voted:
                del VOTES[votee]
            break

    if voted not in VOTES:
        VOTES[voted] = UserList()
    if wrapper.source not in VOTES[voted]:
        VOTES[voted].append(wrapper.source)
        channels.Main.send(messages["player_vote"].format(
            wrapper.source, voted))

    global LAST_VOTES
    LAST_VOTES = None  # reset

    chk_decision(var)
Beispiel #7
0
    def on_transition_day_begin2(evt, var):
        for shaman, (victim, target) in SHAMANS.items():
            totem = TOTEMS[shaman]
            if totem == "death":  # this totem stacks
                if shaman not in DEATH:
                    DEATH[shaman] = UserList()
                DEATH[shaman].append(victim)
            elif totem == "protection":  # this totem stacks
                PROTECTION.append(victim)
            elif totem == "revealing":
                REVEALING.add(victim)
            elif totem == "narcolepsy":
                NARCOLEPSY.add(victim)
            elif totem == "silence":
                SILENCE.add(victim)
            elif totem == "desperation":
                DESPERATION.add(victim)
            elif totem == "impatience":  # this totem stacks
                IMPATIENCE.append(victim)
            elif totem == "pacifism":  # this totem stacks
                PACIFISM.append(victim)
            elif totem == "influence":
                INFLUENCE.add(victim)
            elif totem == "exchange":
                EXCHANGE.add(victim)
            elif totem == "lycanthropy":
                LYCANTHROPY.add(victim)
            elif totem == "luck":
                LUCK.add(victim)
            elif totem == "pestilence":
                PESTILENCE.add(victim)
            elif totem == "retribution":
                RETRIBUTION.add(victim)
            elif totem == "misdirection":
                MISDIRECTION.add(victim)
            elif totem == "deceit":
                DECEIT.add(victim)
            # other totem types possibly handled in an earlier event,
            # as such there is no else: clause here

            if target is not victim:
                shaman.send(messages["totem_retarget"].format(victim))
            LASTGIVEN[shaman] = victim

        havetotem.extend(filter(None, LASTGIVEN.values()))
Beispiel #8
0
def give_totem(var, wrapper, target, prefix, role, msg):
    """Give a totem to a player. Return the value of SHAMANS[user]."""

    orig_target = target
    orig_role = get_main_role(orig_target)

    evt = Event("targeted_command", {
        "target": target,
        "misdirection": True,
        "exchange": True
    })
    if not evt.dispatch(var, wrapper.source, target):
        return

    target = evt.data["target"]
    targrole = get_main_role(target)

    wrapper.send(messages["shaman_success"].format(prefix, msg, orig_target))
    debuglog("{0} ({1}) TOTEM: {2} ({3}) as {4} ({5})".format(
        wrapper.source, role, target, targrole, orig_target, orig_role))

    return UserList((target, orig_target))
Beispiel #9
0
class SleepyMode(GameMode):
    """A small village has become the playing ground for all sorts of supernatural beings."""
    def __init__(self, arg=""):
        super().__init__(arg)
        self.ROLE_GUIDE = {
            10: [
                "wolf", "werecrow", "traitor", "cultist", "seer", "prophet",
                "priest", "dullahan", "cursed villager", "blessed villager"
            ],
            12: ["wolf(2)", "vigilante"],
            15: ["wolf(3)", "detective", "vengeful ghost"],
            18: ["wolf(4)", "harlot", "monster"],
            21: ["wolf(5)", "village drunk", "monster(2)", "gunner"],
        }
        # Make sure priest is always prophet AND blessed, and that drunk is always gunner
        self.SECONDARY_ROLES["blessed villager"] = ["priest"]
        self.SECONDARY_ROLES["prophet"] = ["priest"]
        self.SECONDARY_ROLES["gunner"] = ["village drunk"]
        self.EVENTS = {
            "dullahan_targets": EventListener(self.dullahan_targets),
            "transition_night_begin": EventListener(self.setup_nightmares),
            "chk_nightdone": EventListener(self.prolong_night),
            "transition_day_begin": EventListener(self.nightmare_kill),
            "del_player": EventListener(self.happy_fun_times),
            "revealroles": EventListener(self.on_revealroles)
        }

    def startup(self):
        super().startup()
        self.having_nightmare = UserList()

        cmd_params = dict(chan=False,
                          pm=True,
                          playing=True,
                          phases=("night", ),
                          users=self.having_nightmare)

        self.north_cmd = command("north", "n", **cmd_params)(functools.partial(
            self.move, "n"))
        self.east_cmd = command("east", "e", **cmd_params)(functools.partial(
            self.move, "e"))
        self.south_cmd = command("south", "s", **cmd_params)(functools.partial(
            self.move, "s"))
        self.west_cmd = command("west", "w", **cmd_params)(functools.partial(
            self.move, "w"))

    def teardown(self):
        from src import decorators
        super().teardown()

        def remove_command(name, command):
            if len(decorators.COMMANDS[name]) > 1:
                decorators.COMMANDS[name].remove(command)
            else:
                del decorators.COMMANDS[name]

        remove_command("north", self.north_cmd)
        remove_command("n", self.north_cmd)
        remove_command("east", self.east_cmd)
        remove_command("e", self.east_cmd)
        remove_command("south", self.south_cmd)
        remove_command("s", self.south_cmd)
        remove_command("west", self.west_cmd)
        remove_command("w", self.west_cmd)

        self.having_nightmare.clear()

    def dullahan_targets(self, evt, var, dullahan, max_targets):
        evt.data["targets"].update(var.ROLES["priest"])

    def setup_nightmares(self, evt, var):
        if random.random() < 1 / 5:
            with var.WARNING_LOCK:
                t = threading.Timer(
                    60, self.do_nightmare,
                    (var, random.choice(get_players()), var.NIGHT_COUNT))
                t.daemon = True
                t.start()

    @handle_error
    def do_nightmare(self, var, target, night):
        if var.PHASE != "night" or var.NIGHT_COUNT != night:
            return
        if target not in get_players():
            return
        self.having_nightmare.clear()
        self.having_nightmare.append(target)
        target.send(messages["sleepy_nightmare_begin"])
        target.send(messages["sleepy_nightmare_navigate"])
        self.correct = [None, None, None]
        self.fake1 = [None, None, None]
        self.fake2 = [None, None, None]
        directions = ["n", "e", "s", "w"]
        self.step = 0
        self.prev_direction = None
        opposite = {"n": "s", "e": "w", "s": "n", "w": "e"}
        for i in range(3):
            corrdir = directions[:]
            f1dir = directions[:]
            f2dir = directions[:]
            if i > 0:
                corrdir.remove(opposite[self.correct[i - 1]])
                f1dir.remove(opposite[self.fake1[i - 1]])
                f2dir.remove(opposite[self.fake2[i - 1]])
            else:
                corrdir.remove("s")
                f1dir.remove("s")
                f2dir.remove("s")
            self.correct[i] = random.choice(corrdir)
            self.fake1[i] = random.choice(f1dir)
            self.fake2[i] = random.choice(f2dir)
        self.prev_direction = "n"
        self.start_direction = "n"
        self.on_path = set()
        self.nightmare_step()

    def nightmare_step(self):
        if self.prev_direction == "n":
            directions = "north, east, and west"
        elif self.prev_direction == "e":
            directions = "north, east, and south"
        elif self.prev_direction == "s":
            directions = "east, south, and west"
        elif self.prev_direction == "w":
            directions = "north, south, and west"

        if self.step == 0:
            self.having_nightmare[0].send(
                messages["sleepy_nightmare_0"].format(directions))
        elif self.step == 1:
            self.having_nightmare[0].send(
                messages["sleepy_nightmare_1"].format(directions))
        elif self.step == 2:
            self.having_nightmare[0].send(
                messages["sleepy_nightmare_2"].format(directions))
        elif self.step == 3:
            if "correct" in self.on_path:
                self.having_nightmare[0].send(
                    messages["sleepy_nightmare_wake"])
                self.having_nightmare.clear()
            elif "fake1" in self.on_path:
                self.having_nightmare[0].send(
                    messages["sleepy_nightmare_fake_1"])
                self.step = 0
                self.on_path = set()
                self.prev_direction = self.start_direction
                self.nightmare_step()
            elif "fake2" in self.on_path:
                self.having_nightmare[0].send(
                    messages["sleepy_nightmare_fake_2"])
                self.step = 0
                self.on_path = set()
                self.prev_direction = self.start_direction
                self.nightmare_step()

    def move(self, direction, var, wrapper, message):
        opposite = {"n": "s", "e": "w", "s": "n", "w": "e"}
        if self.prev_direction == opposite[direction]:
            wrapper.pm(messages["sleepy_nightmare_invalid_direction"])
            return
        advance = False
        if ("correct" in self.on_path
                or self.step == 0) and self.correct[self.step] == direction:
            self.on_path.add("correct")
            advance = True
        else:
            self.on_path.discard("correct")
        if ("fake1" in self.on_path
                or self.step == 0) and self.fake1[self.step] == direction:
            self.on_path.add("fake1")
            advance = True
        else:
            self.on_path.discard("fake1")
        if ("fake2" in self.on_path
                or self.step == 0) and self.fake2[self.step] == direction:
            self.on_path.add("fake2")
            advance = True
        else:
            self.on_path.discard("fake2")
        if advance:
            self.step += 1
            self.prev_direction = direction
        else:
            self.step = 0
            self.on_path = set()
            self.prev_direction = self.start_direction
            wrapper.pm(messages["sleepy_nightmare_restart"])
        self.nightmare_step()

    def prolong_night(self, evt, var):
        if self.having_nightmare:
            evt.data["actedcount"] = -1

    def nightmare_kill(self, evt, var):
        if self.having_nightmare and self.having_nightmare[0] in get_players():
            add_dying(var, self.having_nightmare[0], "bot", "night_kill")
            self.having_nightmare[0].send(messages["sleepy_nightmare_death"])
            del self.having_nightmare[0]

    def happy_fun_times(self, evt, var, player, all_roles, death_triggers):
        if death_triggers:
            if evt.params.main_role == "priest":
                turn_chance = 3 / 4
                seers = [
                    p for p in get_players(("seer", ))
                    if random.random() < turn_chance
                ]
                harlots = [
                    p for p in get_players(("harlot", ))
                    if random.random() < turn_chance
                ]
                cultists = [
                    p for p in get_players(("cultist", ))
                    if random.random() < turn_chance
                ]
                channels.Main.send(messages["sleepy_priest_death"])
                for seer in seers:
                    change_role(var,
                                seer,
                                "seer",
                                "doomsayer",
                                message="sleepy_doomsayer_turn")
                for harlot in harlots:
                    change_role(var,
                                harlot,
                                "harlot",
                                "succubus",
                                message="sleepy_succubus_turn")
                for cultist in cultists:
                    change_role(var,
                                cultist,
                                "cultist",
                                "demoniac",
                                message="sleepy_demoniac_turn")

    def on_revealroles(self, evt, var, wrapper):
        if self.having_nightmare:
            evt.data["output"].append(
                "\u0002having nightmare\u0002: {0}".format(
                    self.having_nightmare[0]))
Beispiel #10
0
#    role knows about the totems they receive. This parameter is keyword-only       #
# 4. Implement the "transition_day_begin" and "transition_night_end" events to give #
#    out totems if the shaman didn't act, and send night messages, respectively.    #
#    Implementation of the "get_role_metadata" event with the "role_categories"     #
#    kind is also necessary for the bot to know that the role exists at all. You    #
#    may look at existing shamans for reference. If your shaman isn't a wolf role,  #
#    the "lycanthropy_role" kind should also be implemented as follows:             #
#    evt.data[role] = {"role": "wolf shaman", "prefix": "shaman"}                   #
#    You will also need to implement your own "give" command; see existing          #
#    shamans for reference, or ask for help in our development channel.             #
#                                                                                   #
# It is generally unneeded to modify this file to add new totems or shaman roles    #
#####################################################################################

DEATH = UserDict()  # type: Dict[users.User, List[users.User]]
PROTECTION = UserList()  # type: List[users.User]
REVEALING = UserSet()  # type: Set[users.User]
NARCOLEPSY = UserSet()  # type: Set[users.User]
SILENCE = UserSet()  # type: Set[users.User]
DESPERATION = UserSet()  # type: Set[users.User]
IMPATIENCE = UserList()  # type: List[users.User]
PACIFISM = UserList()  # type: List[users.User]
INFLUENCE = UserSet()  # type: Set[users.User]
EXCHANGE = UserSet()  # type: Set[users.User]
LYCANTHROPY = UserSet()  # type: Set[users.User]
LUCK = UserSet()  # type: Set[users.User]
PESTILENCE = UserSet()  # type: Set[users.User]
RETRIBUTION = UserSet()  # type: Set[users.User]
MISDIRECTION = UserSet()  # type: Set[users.User]
DECEIT = UserSet()  # type: Set[users.User]
Beispiel #11
0
#    role knows about the totems they receive. This parameter is keyword-only       #
# 4. Implement the "transition_day_begin" and "transition_night_end" events to give #
#    out totems if the shaman didn't act, and send night messages, respectively.    #
#    Implementation of the "get_role_metadata" event with the "role_categories"     #
#    kind is also necessary for the bot to know that the role exists at all. You    #
#    may look at existing shamans for reference. If your shaman isn't a wolf role,  #
#    the "lycanthropy_role" kind should also be implemented as follows:             #
#    evt.data[role] = {"role": "wolf shaman", "prefix": "shaman"}                   #
#    You will also need to implement your own "give" command; see existing          #
#    shamans for reference, or ask for help in our development channel.             #
#                                                                                   #
# It is generally unneeded to modify this file to add new totems or shaman roles    #
#####################################################################################

DEATH = UserDict()  # type: UserDict[users.User, UserList]
PROTECTION = UserList()
REVEALING = UserSet()
NARCOLEPSY = UserSet()
SILENCE = UserSet()
DESPERATION = UserSet()
IMPATIENCE = UserList()
PACIFISM = UserList()
INFLUENCE = UserSet()
EXCHANGE = UserSet()
LYCANTHROPY = UserSet()
LUCK = UserSet()
PESTILENCE = UserSet()
RETRIBUTION = UserSet()
MISDIRECTION = UserSet()
DECEIT = UserSet()
Beispiel #12
0
    def wolf_kill(var, wrapper, message):
        """Kill one or more players as a wolf."""
        pieces = re.split(" +", message)
        targets = []
        orig = []

        nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
        nevt.dispatch(var)
        num_kills = nevt.data["numkills"]

        if not num_kills:
            if nevt.data["message"]:
                wrapper.pm(messages[nevt.data["message"]])
            return

        if len(pieces) < num_kills:
            wrapper.pm(messages["wolf_must_target_multiple"])
            return

        for targ in pieces[:num_kills]:
            target = get_target(var,
                                wrapper,
                                targ,
                                not_self_message="no_suicide")
            if target is None:
                return

            if is_known_wolf_ally(var, wrapper.source, target):
                wrapper.pm(messages["wolf_no_target_wolf"])
                return

            if target in orig:
                wrapper.pm(messages["wolf_must_target_multiple"])
                return

            orig.append(target)
            target = try_misdirection(var, wrapper.source, target)
            if try_exchange(var, wrapper.source, target):
                return

            targets.append(target)

        KILLS[wrapper.source] = UserList(targets)

        if len(orig) > 1:
            # TODO: Expand this so we can support arbitrarily many kills (instead of just one or two)
            wrapper.pm(messages["player_kill_multiple"].format(*orig))
            msg = messages["wolfchat_kill_multiple"].format(
                wrapper.source, *orig)
            debuglog("{0} ({1}) KILL: {2} ({4}) and {3} ({5})".format(
                wrapper.source, rolename, *targets, get_main_role(targets[0]),
                get_main_role(targets[1])))
        else:
            wrapper.pm(messages["player_kill"].format(orig[0]))
            msg = messages["wolfchat_kill"].format(wrapper.source, orig[0])
            debuglog("{0} ({1}) KILL: {2} ({3})".format(
                wrapper.source, rolename, targets[0],
                get_main_role(targets[0])))

        send_wolfchat_message(var,
                              wrapper.source,
                              msg,
                              Wolf,
                              role=rolename,
                              command="kill")