예제 #1
0
파일: lycanthropy.py 프로젝트: lykoss/lykos
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))
예제 #2
0
파일: doctor.py 프로젝트: lykoss/lykos
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)))
예제 #3
0
파일: wolfbot.py 프로젝트: lykoss/lykos
def main():
    evt = Event("init", {})
    evt.dispatch()
    src.plog("Connecting to {0}:{1}{2}".format(botconfig.HOST, "+" if botconfig.USE_SSL else "", botconfig.PORT))
    cli = IRCClient(
                      {"privmsg": lambda *s: None,
                       "notice": lambda *s: None,
                       "": handler.unhandled},
                     host=botconfig.HOST,
                     port=botconfig.PORT,
                     authname=botconfig.USERNAME,
                     password=botconfig.PASS,
                     nickname=botconfig.NICK,
                     ident=botconfig.IDENT,
                     real_name=botconfig.REALNAME,
                     sasl_auth=botconfig.SASL_AUTHENTICATION,
                     server_pass=botconfig.SERVER_PASS,
                     use_ssl=botconfig.USE_SSL,
                     cert_verify=var.SSL_VERIFY,
                     cert_fp=var.SSL_CERTFP,
                     client_certfile=var.SSL_CERTFILE,
                     client_keyfile=var.SSL_KEYFILE,
                     cipher_list=var.SSL_CIPHERS,
                     tokenbucket=TokenBucket(var.IRC_TB_BURST, var.IRC_TB_DELAY, init=var.IRC_TB_INIT),
                     connect_cb=handler.connect_callback,
                     stream_handler=src.stream,
    )
    cli.mainLoop()
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
파일: hooks.py 프로젝트: lykoss/lykos
def mode_change(cli, rawnick, chan, mode, *targets):
    """Update the channel and user modes whenever a mode change occurs.

    Ordering and meaning of arguments for a MODE change:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick of the mode setter/actor
    2 - The channel (target) of the mode change
    3 - The mode changes
    * - The targets of the modes (if any)

    This takes care of properly updating all relevant users and the
    channel modes to make sure we remain internally consistent.

    """

    if chan == users.Bot.nick: # we only see user modes set to ourselves
        users.Bot.modes.update(mode)
        return

    if "!" not in rawnick:
        # Only sync modes if a server changed modes because
        # 1) human ops probably know better
        # 2) other bots might start a fight over modes
        # 3) recursion; we see our own mode changes.
        evt = Event("sync_modes", {})
        evt.dispatch(var)
        return

    actor = users._get(rawnick, allow_none=True) # FIXME
    target = channels.add(chan, cli)
    target.queue("mode_change", {"mode": mode, "targets": targets}, (var, actor, target))
예제 #7
0
파일: hunter.py 프로젝트: FastLizard4/lykos
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)
예제 #8
0
파일: priest.py 프로젝트: lykoss/lykos
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)
예제 #9
0
파일: succubus.py 프로젝트: lykoss/lykos
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)))
예제 #10
0
파일: lycanthropy.py 프로젝트: lykoss/lykos
def on_reconfigure_stats(evt, var, roleset, reason):
    from src.roles.helper.wolves import get_wolfchat_roles
    if reason != "howl" or not SCOPE:
        return

    evt2 = Event("get_role_metadata", {})
    evt2.dispatch(var, "lycanthropy_role")

    roles = {}

    wolfchat = get_wolfchat_roles(var)
    for role, count in roleset.items():
        if role in wolfchat or count == 0 or role not in SCOPE:
            continue
        if role in evt2.data and "role" in evt2.data[role]:
            roles[role] = evt2.data[role]["role"]
        else:
            roles[role] = "wolf"

    if roles and roleset in evt.data["new"]:
        evt.data["new"].remove(roleset)

    for role, new_role in roles.items():
        rs = roleset.copy()
        rs[role] -= 1
        rs[new_role] = rs.get(new_role, 0) + 1
        evt.data["new"].append(rs)
예제 #11
0
파일: augur.py 프로젝트: lykoss/lykos
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)
예제 #12
0
파일: harlot.py 프로젝트: lykoss/lykos
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))
예제 #13
0
파일: traitor.py 프로젝트: lykoss/lykos
def on_update_stats3(evt, var, player, mainrole, revealrole, allroles):
    # if this is a night death and we know for sure that wolves (and only wolves)
    # killed, then that kill cannot be traitor as long as they're in wolfchat.
    # check if the reason == "night_death", otherwise it's probably a chained death which
    # can be traitor even if only wolves killed, so we short-circuit there as well
    # TODO: luck/misdirection totem can leak info due to our short-circuit below this comment.
    # If traitor dies due to one of these totems, both traitor count and villager count is reduced by
    # 1. If traitor does not die, and no other roles can kill (no death totems), then traitor count is unchanged
    # and villager count is reduced by 1. We should make it so that both counts are reduced when
    # luck/misdirection are potentially in play.
    # FIXME: this doesn't check RESTRICT_WOLFCHAT to see if traitor was removed from wolfchat. If
    # they've been removed, they can be killed like normal so all this logic is meaningless.
    if "traitor" not in evt.data["possible"] or evt.params.reason != "night_death" or mainrole == "traitor":
        return
    if var.PHASE == "day" and var.GAMEPHASE == "night":
        mevt = Event("get_role_metadata", {})
        mevt.dispatch(var, "night_kills")
        nonwolf = 0
        total = 0
        for role, num in mevt.data.items():
            if role != "wolf":
                nonwolf += num
            total += num
        if nonwolf == 0:
            evt.data["possible"].discard("traitor")
            return
예제 #14
0
파일: lynchimmune.py 프로젝트: lykoss/lykos
def try_lynch_immunity(var, user) -> bool:
    if user in IMMUNITY:
        reason = IMMUNITY[user].pop() # get a random reason
        evt = Event("lynch_immunity", {"immune": False})
        evt.dispatch(var, user, reason)
        return evt.data["immune"]

    return False
예제 #15
0
파일: wolves.py 프로젝트: lykoss/lykos
def on_new_role(evt, var, player, old_role):
    wcroles = get_wolfchat_roles(var)

    if old_role is None:
        # initial role assignment; don't do all the logic below about notifying other wolves and such
        if evt.data["role"] in wcroles:
            evt.data["in_wolfchat"] = True
        return

    sayrole = evt.data["role"]
    if sayrole in Hidden:
        sayrole = var.HIDDEN_ROLE
    an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else ""

    if player in KILLS:
        del KILLS[player]

    if old_role not in wcroles and evt.data["role"] in wcroles:
        # a new wofl has joined the party, give them tummy rubs and the wolf list
        # and let the other wolves know to break out the confetti and villager steaks
        wofls = get_players(wcroles)
        evt.data["in_wolfchat"] = True
        if wofls:
            new_wolves = []
            for wofl in wofls:
                wofl.queue_message(messages["wolfchat_new_member"].format(player, an, sayrole))
            wofl.send_messages()
        else:
            return # no other wolves, nothing else to do

        pl = get_players()
        if player in pl:
            pl.remove(player)
        random.shuffle(pl)
        pt = []
        wevt = Event("wolflist", {"tags": set()})
        for p in pl:
            prole = get_main_role(p)
            wevt.data["tags"].clear()
            wevt.dispatch(var, p, player)
            tags = " ".join(wevt.data["tags"])
            if prole in wcroles:
                if tags:
                    tags += " "
                pt.append("\u0002{0}\u0002 ({1}{2})".format(p, tags, prole))
            elif tags:
                pt.append("{0} ({1})".format(p, tags))
            else:
                pt.append(p.nick)

        evt.data["messages"].append(messages["players_list"].format(", ".join(pt)))

        if var.PHASE == "night" and evt.data["role"] in Wolf & Killer:
            # inform the new wolf that they can kill and stuff
            nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
            nevt.dispatch(var)
            if not nevt.data["numkills"] and nevt.data["message"]:
                evt.data["messages"].append(messages[nevt.data["message"]])
예제 #16
0
파일: wolves.py 프로젝트: lykoss/lykos
def wolf_can_kill(var, wolf):
    # a wolf can kill if wolves in general can kill, and the wolf is a Killer
    # this is a utility function meant to be used by other wolf role modules
    nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]
    if num_kills == 0:
        return False
    wolfroles = get_all_roles(wolf)
    return bool(Wolf & Killer & wolfroles)
예제 #17
0
파일: channels.py 프로젝트: lykoss/lykos
 def remove_user(self, user):
     self.users.remove(user)
     for mode in Features["PREFIX"].values():
         if mode in self.modes:
             self.modes[mode].discard(user)
             if not self.modes[mode]:
                 del self.modes[mode]
     del user.channels[self]
     if not user.channels: # Only fire if the user left all channels
         event = Event("cleanup_user", {})
         event.dispatch(var, user)
예제 #18
0
파일: protection.py 프로젝트: lykoss/lykos
def remove_all_protections(var, target, attacker, attacker_role, reason, scope=All):
    """Remove all protections from a player."""
    if target not in PROTECTIONS:
        return

    for protector, entries in list(PROTECTIONS[target].items()):
        for cat, protector_role in entries:
            if scope & cat:
                evt = Event("remove_protection", {"remove": False})
                evt.dispatch(var, target, attacker, attacker_role, protector, protector_role, reason)
                if evt.data["remove"]:
                    PROTECTIONS[target][protector].remove((cat, protector_role))
예제 #19
0
파일: wolves.py 프로젝트: lykoss/lykos
    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")
예제 #20
0
파일: utilities.py 프로젝트: lykoss/lykos
def complete_role(var, role):
    from src.cats import ROLES
    if role not in ROLES:
        special_keys = {"lover"}
        evt = Event("get_role_metadata", {})
        evt.dispatch(var, "special_keys")
        special_keys = functools.reduce(lambda x, y: x | y, evt.data.values(), special_keys)
        if role.lower() in var.ROLE_ALIASES:
            matches = (var.ROLE_ALIASES[role.lower()],)
        else:
            matches = complete_match(role, ROLES.keys() | special_keys)
        if not matches:
            return []
        return matches
    return [role]
예제 #21
0
파일: hooks.py 프로젝트: lykoss/lykos
def who_reply(cli, bot_server, bot_nick, chan, ident, host, server, nick, status, hopcount_gecos):
    """Handle WHO replies for servers without WHOX support.

    Ordering and meaning of arguments for a bare WHO response:

    0 - The IRCClient instance (like everywhere else)
    1 - The server the requester (i.e. the bot) is on
    2 - The nickname of the requester (i.e. the bot)
    3 - The channel the request was made on
    4 - The ident of the user in this reply
    5 - The hostname of the user in this reply
    6 - The server the user in this reply is on
    7 - The nickname of the user in this reply
    8 - The status (H = Not away, G = Away, * = IRC operator, @ = Opped in the channel in 4, + = Voiced in the channel in 4)
    9 - The hop count and realname (gecos)

    This fires off the "who_result" event, and dispatches it with three
    arguments, the game state namespace, a Channel, and a User. Less
    important attributes can be accessed via the event.params namespace.

    """

    hop, realname = hopcount_gecos.split(" ", 1)
    hop = int(hop)
    # We throw away the information about the operness of the user, but we probably don't need to care about that
    # We also don't directly pass which modes they have, since that's already on the channel/user
    is_away = ("G" in status)

    modes = {Features["PREFIX"].get(s) for s in status} - {None}

    user = users._add(cli, nick=nick, ident=ident, host=host, realname=realname) # FIXME
    ch = None
    if not channels.predicate(chan): # returns True if it's not a channel
        ch = channels.add(chan, cli)

        if ch not in user.channels:
            user.channels[ch] = modes
            ch.users.add(user)
            for mode in modes:
                if mode not in ch.modes:
                    ch.modes[mode] = set()
                ch.modes[mode].add(user)

    event = Event("who_result", {}, away=is_away, data=0, ip_address=None, server=server, hop_count=hop, idle_time=None, extended_who=False)
    event.dispatch(var, ch, user)

    if ch is channels.Main and not users.exists(nick): # FIXME
        users.add(nick, ident=ident, host=host, account="*", inchan=True, modes=modes, moded=set())
예제 #22
0
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)
예제 #23
0
파일: dying.py 프로젝트: lykoss/lykos
def kill_players(var, *, end_game: bool = True) -> bool:
    """
    Kill all players marked as dying.

    This function is not re-entrant; do not call it inside of a del_player or kill_players event listener.
    This function does not print anything to the channel; code which calls add_dying should print things as appropriate.

    :param var: The game state
    :param end_game: Whether or not to check for win conditions and perform state transitions (temporary)
    :returns: True if the game is ending (temporary)
    """
    t = time.time()

    with var.GRAVEYARD_LOCK: # FIXME
        if not var.GAME_ID or var.GAME_ID > t:
            #  either game ended, or a new game has started
            return

        dead = set()

        while DYING:
            player, (killer_role, reason, death_triggers) = DYING.popitem()
            main_role = get_main_role(player)
            reveal_role = get_reveal_role(player)
            all_roles = get_all_roles(player)
            # kill them off
            del var.MAIN_ROLES[player]
            for role in all_roles:
                var.ROLES[role].remove(player)
            dead.add(player)
            var.DEAD.add(player)
            # notify listeners that the player died for possibility of chained deaths
            evt = Event("del_player", {},
                        killer_role=killer_role,
                        main_role=main_role,
                        reveal_role=reveal_role,
                        reason=reason)
            evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
            evt.dispatch(var, player, all_roles, evt_death_triggers)

        # notify listeners that all deaths have resolved
        # FIXME: end_game is a temporary hack until we move state transitions into the event loop
        # (priority 10 listener sets prevent_default if end_game=True and game is ending; that's another temporary hack)
        # Once hacks are removed, this function will not have any return value and the end_game kwarg will go away
        evt = Event("kill_players", {}, end_game=end_game)
        return not evt.dispatch(var, dead)
예제 #24
0
파일: dullahan.py 프로젝트: lykoss/lykos
def on_new_role(evt, var, player, old_role):
    if player in TARGETS and old_role == "dullahan" and evt.data["role"] != "dullahan":
        del KILLS[:player:]
        del TARGETS[player]

    if player not in TARGETS and evt.data["role"] == "dullahan":
        ps = get_players()
        max_targets = math.ceil(8.1 * math.log(len(ps), 10) - 5)
        TARGETS[player] = UserSet()

        dull_targets = Event("dullahan_targets", {"targets": TARGETS[player]}) # support sleepy
        dull_targets.dispatch(var, player, max_targets)

        ps.remove(player)
        while len(TARGETS[player]) < max_targets:
            target = random.choice(ps)
            ps.remove(target)
            TARGETS[player].add(target)
예제 #25
0
파일: wolves.py 프로젝트: lykoss/lykos
def on_chk_nightdone(evt, var):
    nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]
    wofls = [x for x in get_players(Wolf & Killer) if not is_silent(var, x)]
    if not num_kills or not wofls:
        return

    evt.data["nightroles"].extend(wofls)
    evt.data["actedcount"] += len(KILLS)
    evt.data["nightroles"].append(users.FakeUser.from_nick("@WolvesAgree@"))
    # check if wolves are actually agreeing or not;
    # only add to count if they actually agree
    # (this is *slighty* less hacky than deducting 1 from actedcount as we did previously)
    kills = set()
    for ls in KILLS.values():
        kills.update(ls)
    # check if wolves are actually agreeing
    if len(kills) == num_kills:
        evt.data["actedcount"] += 1
예제 #26
0
파일: oracle.py 프로젝트: lykoss/lykos
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

    for i in range(2): # need to go through loop twice
        iswolf = False
        if targrole in Cursed:
            targrole = "wolf"
            iswolf = True
        elif targrole in Safe | Innocent:
            targrole = var.HIDDEN_ROLE
        elif targrole in Wolf:
            targrole = "wolf"
            iswolf = True
        else:
            targrole = var.HIDDEN_ROLE

        if i:
            break

        evt = Event("see", {"role": targrole})
        evt.dispatch(var, wrapper.source, target)
        targrole = evt.data["role"]

    wrapper.send(messages["oracle_success"].format(target, "" if iswolf else "\u0002not\u0002 ", "\u0002" if iswolf else ""))
    debuglog("{0} (oracle) SEE: {1} ({2}) (Wolf: {3})".format(wrapper.source, target, trole, str(iswolf)))

    SEEN.add(wrapper.source)
예제 #27
0
파일: protection.py 프로젝트: lykoss/lykos
def try_protection(var, target, attacker, attacker_role, reason):
    """Attempt to protect the player, and return a list of messages or None."""
    prots = []
    for protector, entries in PROTECTIONS.get(target, {}).items():
        for scope, protector_role in entries:
            if attacker_role in scope:
                entry = (protector, protector_role, scope)
                prots.append(entry)

    try_evt = Event("try_protection", {"protections": prots, "messages": []})
    if not try_evt.dispatch(var, target, attacker, attacker_role, reason) or not try_evt.data["protections"]:
        return None

    protector, protector_role, scope = try_evt.data["protections"].pop(0)

    PROTECTIONS[target][protector].remove((scope, protector_role))

    prot_evt = Event("player_protected", {"messages": try_evt.data["messages"]})
    prot_evt.dispatch(var, target, attacker, attacker_role, protector, protector_role, reason)

    return prot_evt.data["messages"]
예제 #28
0
파일: exchange.py 프로젝트: lykoss/lykos
def try_exchange(var, actor, target):
    """Check if an exchange is happening. Return True if the exchange occurs."""
    if actor is target or target not in EXCHANGE:
        return False

    EXCHANGE.remove(target)

    role = get_main_role(actor)
    target_role = get_main_role(target)

    actor_role = change_role(var, actor, role, target_role, inherit_from=target)
    target_role = change_role(var, target, target_role, role, inherit_from=actor)

    if actor_role == target_role: # swap state of two players with the same role
        evt = Event("swap_role_state", {"actor_messages": [], "target_messages": []})
        evt.dispatch(var, actor, target, actor_role)

        actor.send(*evt.data["actor_messages"])
        target.send(*evt.data["target_messages"])

    return True
예제 #29
0
파일: detective.py 프로젝트: lykoss/lykos
def investigate(var, wrapper, message):
    """Investigate a player to determine their exact role."""
    if wrapper.source in INVESTIGATED:
        wrapper.send(messages["already_investigated"])
        return

    target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_investigate_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)

    evt = Event("investigate", {"role": targrole})
    evt.dispatch(var, wrapper.source, target)
    targrole = evt.data["role"]

    INVESTIGATED.add(wrapper.source)
    wrapper.send(messages["investigate_success"].format(target, targrole))
    debuglog("{0} (detective) ID: {1} ({2})".format(wrapper.source, target, targrole))

    if random.random() < var.DETECTIVE_REVEALED_CHANCE:  # a 2/5 chance (should be changeable in settings)
        # The detective's identity is compromised!
        wcroles = Wolfchat
        if var.RESTRICT_WOLFCHAT & var.RW_REM_NON_WOLVES:
            if var.RESTRICT_WOLFCHAT & var.RW_TRAITOR_NON_WOLF:
                wcroles = Wolf
            else:
                wcroles = Wolf | {"traitor"}

        wolves = get_all_players(wcroles)
        if wolves:
            for wolf in wolves:
                wolf.queue_message(messages["detective_reveal"].format(wrapper.source))
            wolf.send_messages()

        debuglog("{0} (detective) PAPER DROP".format(wrapper.source))
예제 #30
0
파일: seer.py 프로젝트: mweinelt/lykos
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

    if targrole in Cursed:
        targrole = "wolf"
    elif targrole in Safe:
        pass # Keep the same role
    elif targrole in Innocent:
        targrole = var.HIDDEN_ROLE
    elif targrole in (Neutral - Win_Stealer - Team_Switcher):
        pass # Keep the same role
    elif targrole in Wolf:
        targrole = "wolf"
    else:
        targrole = var.HIDDEN_ROLE

    evt = Event("see", {"role": targrole})
    evt.dispatch(var, wrapper.source, target)
    targrole = evt.data["role"]

    wrapper.send(messages["seer_success"].format(target, targrole))
    debuglog("{0} (seer) SEE: {1} ({2}) as {3}".format(wrapper.source, target, trole, targrole))

    SEEN.add(wrapper.source)
예제 #31
0
파일: mystic.py 프로젝트: Fudster/lykos
def on_exchange(evt, var, actor, target, actor_role, target_role):
    if actor_role not in ("mystic", "wolf mystic") and target_role not in (
            "mystic", "wolf mystic"):
        return

    special = set(
        get_players(("harlot", "priest", "prophet", "matchmaker", "doctor",
                     "hag", "sorcerer", "turncoat", "clone")))
    evt2 = Event("get_special", {"special": special})
    evt2.dispatch(var)
    pl = set(get_players())
    wolves = set(get_players(var.WOLFTEAM_ROLES))
    neutral = set(get_players(var.TRUE_NEUTRAL_ROLES))
    special = evt2.data["special"]

    if target_role == "wolf mystic" and actor_role != "wolf mystic":
        # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals
        numvills = len(special & (pl - wolves - neutral))
        evt.data["actor_messages"].append(messages["wolf_mystic_info"].format(
            "are" if numvills != 1 else "is", numvills,
            "s" if numvills != 1 else ""))
    elif target_role == "mystic" and actor_role != "mystic":
        numevil = len(wolves)
        evt.data["actor_messages"].append(messages["mystic_info"].format(
            "are" if numevil != 1 else "is", numevil,
            "s" if numevil != 1 else ""))

    if actor_role == "wolf mystic" and target_role != "wolf mystic":
        # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals
        numvills = len(special & (pl - wolves - neutral))
        evt.data["target_messages"].append(messages["wolf_mystic_info"].format(
            "are" if numvills != 1 else "is", numvills,
            "s" if numvills != 1 else ""))
    elif actor_role == "mystic" and target_role != "mystic":
        numevil = len(wolves)
        evt.data["target_messages"].append(messages["mystic_info"].format(
            "are" if numevil != 1 else "is", numevil,
            "s" if numevil != 1 else ""))
예제 #32
0
def on_new_role(evt, var, player, old_role):
    wcroles = get_wolfchat_roles(var)

    if old_role is None:
        # initial role assignment; don't do all the logic below about notifying other wolves and such
        if evt.data["role"] in wcroles:
            evt.data["in_wolfchat"] = True
        return

    sayrole = evt.data["role"]
    if sayrole in Hidden:
        sayrole = var.HIDDEN_ROLE

    if player in KILLS:
        del KILLS[player]

    if old_role not in wcroles and evt.data["role"] in wcroles:
        # a new wofl has joined the party, give them tummy rubs and the wolf list
        # and let the other wolves know to break out the confetti and villager steaks
        wofls = get_players(wcroles)
        evt.data["in_wolfchat"] = True
        if wofls:
            for wofl in wofls:
                wofl.queue_message(messages["wolfchat_new_member"].format(
                    player, sayrole))
            wofl.send_messages()
        else:
            return  # no other wolves, nothing else to do

        evt.data["messages"].append(messages["players_list"].format(
            get_wolflist(var, player)))

        if var.PHASE == "night" and evt.data["role"] in Wolf & Killer:
            # inform the new wolf that they can kill and stuff
            nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
            nevt.dispatch(var)
            if not nevt.data["numkills"] and nevt.data["message"]:
                evt.data["messages"].append(messages[nevt.data["message"]])
예제 #33
0
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(var.WOLFTEAM_ROLES)
    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
    evt = Event("targeted_command", {
        "target": target,
        "misdirection": True,
        "exchange": False
    })
    evt.dispatch(var, wrapper.source, target)
    if evt.prevent_default:
        return
    target = evt.data["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)))
예제 #34
0
파일: assassin.py 프로젝트: Satssuki/lykos
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
    if player in TARGETED.values():
        for x, y in list(TARGETED.items()):
            if y is player:
                del TARGETED[x]
                PREV_ACTED.discard(x)

    if death_triggers and "assassin" in allroles and player in TARGETED:
        target = TARGETED[player]
        del TARGETED[player]
        PREV_ACTED.discard(player)
        if target in evt.data["pl"]:
            prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
            aevt = Event("assassinate", {"pl": evt.data["pl"], "target": target},
                del_player=evt.params.del_player,
                deadlist=evt.params.deadlist,
                original=evt.params.original,
                refresh_pl=evt.params.refresh_pl,
                message_prefix="assassin_fail_",
                source="assassin",
                killer=player,
                killer_mainrole=mainrole,
                killer_allroles=allroles,
                prots=prots)

            while len(prots) > 0:
                # an event can read the current active protection and cancel the assassination
                # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
                # so that it cannot be used again (if the protection is meant to be usable once-only)
                if not aevt.dispatch(var, player, target, prots[0]):
                    pl = aevt.data["pl"]
                    if target is not aevt.data["target"]:
                        target = aevt.data["target"]
                        prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
                        aevt.params.prots = prots
                        continue
                    break
                prots.popleft()

            if not prots:
                if var.ROLE_REVEAL in ("on", "team"):
                    role = get_reveal_role(target)
                    an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                    message = messages["assassin_success"].format(player, target, an, role)
                else:
                    message = messages["assassin_success_no_reveal"].format(player, target)
                channels.Main.send(message)
                debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target)))
                evt.params.del_player(target, end_game=False, killer_role=mainrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
                evt.data["pl"] = evt.params.refresh_pl(aevt.data["pl"])
예제 #35
0
def get_reveal_role(nick):
    if var.HIDDEN_TRAITOR and get_role(nick) == "traitor":
        role = var.DEFAULT_ROLE
    elif var.HIDDEN_AMNESIAC and nick in var.ORIGINAL_ROLES["amnesiac"]:
        role = "amnesiac"
    elif var.HIDDEN_CLONE and nick in var.ORIGINAL_ROLES["clone"]:
        role = "clone"
    else:
        role = get_role(nick)

    evt = Event("get_reveal_role", {"role": role})
    evt.dispatch(var, nick)
    role = evt.data["role"]

    if var.ROLE_REVEAL != "team":
        return role

    if role in var.WOLFTEAM_ROLES:
        return "wolf"
    elif role in var.TRUE_NEUTRAL_ROLES:
        return "neutral player"
    else:
        return "villager"
예제 #36
0
def get_reveal_role(nick):
    if var.HIDDEN_TRAITOR and get_role(nick) == "traitor":
        role = var.DEFAULT_ROLE
    elif var.HIDDEN_AMNESIAC and nick in var.ORIGINAL_ROLES["amnesiac"]:
        role = "amnesiac"
    elif var.HIDDEN_CLONE and nick in var.ORIGINAL_ROLES["clone"]:
        role = "clone"
    else:
        role = get_role(nick)

    evt = Event("get_reveal_role", {"role": role})
    evt.dispatch(var, nick)
    role = evt.data["role"]

    if var.ROLE_REVEAL != "team":
        return role

    if role in var.WOLFTEAM_ROLES:
        return "wolf"
    elif role in var.TRUE_NEUTRAL_ROLES:
        return "neutral player"
    else:
        return "villager"
예제 #37
0
def on_transition_day_begin(evt, var):
    # Select random totem recipients if shamans didn't act
    pl = get_players()
    for shaman in get_players(("crazed shaman",)):
        if shaman not in SHAMANS and shaman.nick not in var.SILENCED:
            ps = pl[:]
            if shaman in LASTGIVEN:
                if LASTGIVEN[shaman] in ps:
                    ps.remove(LASTGIVEN[shaman])
            levt = Event("get_random_totem_targets", {"targets": ps})
            levt.dispatch(var, shaman)
            ps = levt.data["targets"]
            if ps:
                target = random.choice(ps)
                dispatcher = MessageDispatcher(shaman, shaman)

                tags = get_tags(var, TOTEMS[shaman])

                SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], tags=tags, role="crazed shaman", msg="")
            else:
                LASTGIVEN[shaman] = None
        elif shaman not in SHAMANS:
            LASTGIVEN[shaman] = None
예제 #38
0
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

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

    target = evt.data["target"]

    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))
예제 #39
0
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
    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"]
    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)))
예제 #40
0
파일: utilities.py 프로젝트: nirvam/lykos
def get_reveal_role(nick):
    # FIXME: make the arg a user instead of a nick
    from src import users
    if var.HIDDEN_AMNESIAC and nick in var.ORIGINAL_ROLES["amnesiac"]:
        role = "amnesiac"
    elif var.HIDDEN_CLONE and nick in var.ORIGINAL_ROLES["clone"]:
        role = "clone"
    else:
        role = get_role(nick)

    evt = Event("get_reveal_role", {"role": role})
    evt.dispatch(var, users._get(nick))
    role = evt.data["role"]

    if var.ROLE_REVEAL != "team":
        return role

    if role in var.WOLFTEAM_ROLES:
        return "wolfteam player"
    elif role in var.TRUE_NEUTRAL_ROLES:
        return "neutral player"
    else:
        return "village member"
예제 #41
0
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))
예제 #42
0
파일: functions.py 프로젝트: rdococ/lykos
def change_role(var,
                player,
                oldrole,
                newrole,
                *,
                inherit_from=None,
                message="new_role"):
    # in_wolfchat is filled as part of priority 4
    # if you wish to modify evt.data["role"], do so in priority 3 or sooner
    evt = Event("new_role", {
        "role": newrole,
        "messages": [],
        "in_wolfchat": False
    },
                inherit_from=inherit_from)
    evt.dispatch(var, player, oldrole)
    newrole = evt.data["role"]

    var.ROLES[oldrole].remove(player)
    var.ROLES[newrole].add(player)
    # only adjust MAIN_ROLES/FINAL_ROLES if we're changing the player's actual role
    if var.MAIN_ROLES[player] == oldrole:
        var.MAIN_ROLES[player] = newrole
        var.FINAL_ROLES[player] = newrole

    # if giving the player a new role during night, don't warn them for not acting
    var.NIGHT_IDLE_EXEMPT.add(player)

    sayrole = newrole
    if sayrole in Hidden:
        sayrole = var.HIDDEN_ROLE

    if message:
        player.send(messages[message].format(sayrole))
    player.send(*evt.data["messages"])

    return newrole
예제 #43
0
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

    evt = Event("targeted_command", {
        "target": target,
        "misdirection": True,
        "exchange": True
    })
    evt.dispatch(var, "visit", wrapper.source, target,
                 frozenset({"immediate"}))
    if evt.prevent_default:
        return
    target = evt.data["target"]
    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))
예제 #44
0
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])
    if not target:
        return

    if wrapper.source is target:
        wrapper.pm(messages["no_suicide"])
        return

    orig = target
    evt = Event("targeted_command", {
        "target": target.nick,
        "misdirection": True,
        "exchange": True
    })
    evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick,
                 frozenset({"detrimental"}))
    if evt.prevent_default:
        return

    target = users._get(
        evt.data["target"]
    )  # FIXME: Need to fix once targeted_command uses the new API

    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_role(target.nick)))
    chk_nightdone(wrapper.client)
예제 #45
0
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))
            prots = deque(var.ACTIVE_PROTECTIONS[target])
            aevt = Event("assassinate", {"pl": evt.data["pl"]},
                         del_player=evt.params.del_player,
                         deadlist=evt.params.deadlist,
                         original=evt.params.original,
                         refresh_pl=evt.params.refresh_pl,
                         message_prefix="dullahan_die_")
            while len(prots) > 0:
                # an event can read the current active protection and cancel the totem
                # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
                # so that it cannot be used again (if the protection is meant to be usable once-only)
                if not aevt.dispatch(cli, var, nick, target, prots[0]):
                    evt.data["pl"] = aevt.data["pl"]
                    return
                prots.popleft()
            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)
예제 #46
0
def try_protection(var, target, attacker, attacker_role, reason):
    """Attempt to protect the player, and return a list of messages or None."""
    prots = []
    for protector, entries in PROTECTIONS.get(target, {}).items():
        for scope, protector_role in entries:
            if attacker_role in scope:
                entry = (protector, protector_role, scope)
                prots.append(entry)

    try_evt = Event("try_protection", {"protections": prots, "messages": []})
    if not try_evt.dispatch(var, target, attacker, attacker_role,
                            reason) or not try_evt.data["protections"]:
        return None

    protector, protector_role, scope = try_evt.data["protections"].pop(0)

    PROTECTIONS[target][protector].remove((scope, protector_role))

    prot_evt = Event("player_protected",
                     {"messages": try_evt.data["messages"]})
    prot_evt.dispatch(var, target, attacker, attacker_role, protector,
                      protector_role, reason)

    return prot_evt.data["messages"]
예제 #47
0
파일: hooks.py 프로젝트: svdermant/lykos
def on_whois_end(cli, bot_server, bot_nick, nick, message):
    """Handle the end of WHOIS and fire events.

    Ordering and meaning of arguments for an end of WHOIS reply:

    0 - The IRCClient instance (like everywhere else)
    1 - The server the requester (i.e. the bot) is on
    2 - The nickname of the requester (i.e. the bot)
    3 - The nickname of the target
    4 - A human-friendly message, usually "End of /WHOIS list."

    This uses data accumulated from the above WHOIS listeners, and
    fires the "who_result" event (once per shared channel with the bot)
    and the "who_end" event with the relevant User instance as the arg.

    """

    values = _whois_pending.pop(nick)
    # check for account change
    new_user = user = values["user"]
    if {user.account, values["account"]} != {None} and not context.equals(
            user.account, values["account"]):
        # first check tests if both are None, and skips over this if so
        old_account = user.account
        user.account = values["account"]
        new_user = users.get(user.nick,
                             user.ident,
                             user.host,
                             values["account"],
                             allow_bot=True)
        Event("account_change", {}, old=user).dispatch(new_user, old_account)

    event = Event("who_result", {}, away=values["away"], data=0, old=user)
    for chan in values["channels"]:
        event.dispatch(chan, new_user)
    Event("who_end", {}, old=user).dispatch(new_user)
예제 #48
0
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])
    if not target:
        return

    if target is wrapper.source:
        wrapper.pm(messages["no_suicide"])
        return

    orig = target
    evt = Event("targeted_command", {
        "target": target.nick,
        "misdirection": True,
        "exchange": True
    })
    evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick,
                 frozenset({"detrimental"}))
    if evt.prevent_default:
        return
    target = users._get(
        evt.data["target"]
    )  # FIXME: Need to fix once targeted_command uses the new API

    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)))

    chk_nightdone(wrapper.client)
예제 #49
0
def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
    special = set(
        list_players(
            ("harlot", "guardian angel", "bodyguard", "priest", "prophet",
             "matchmaker", "shaman", "doctor", "hag", "sorcerer", "turncoat",
             "clone", "crazed shaman", "piper", "succubus")))
    evt2 = Event("get_special", {"special": special})
    evt2.dispatch(cli, var)
    pl = set(list_players())
    wolves = set(list_players(var.WOLFTEAM_ROLES))
    neutral = set(list_players(var.TRUE_NEUTRAL_ROLES))
    special = evt2.data["special"]

    if nick_role == "wolf mystic" and actor_role != "wolf mystic":
        # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals
        numvills = len(special & (pl - wolves - neutral))
        evt.data["actor_messages"].append(messages["wolf_mystic_info"].format(
            "are" if numvills != 1 else "is", numvills,
            "s" if numvills != 1 else ""))
    elif nick_role == "mystic" and actor_role != "mystic":
        numevil = len(wolves)
        evt.data["actor_messages"].append(messages["mystic_info"].format(
            "are" if numevil != 1 else "is", numevil,
            "s" if numevil != 1 else ""))

    if actor_role == "wolf mystic" and nick_role != "wolf mystic":
        # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals
        numvills = len(special & (pl - wolves - neutral))
        evt.data["nick_messages"].append(messages["wolf_mystic_info"].format(
            "are" if numvills != 1 else "is", numvills,
            "s" if numvills != 1 else ""))
    elif actor_role == "mystic" and nick_role != "mystic":
        numevil = len(wolves)
        evt.data["nick_messages"].append(messages["mystic_info"].format(
            "are" if numevil != 1 else "is", numevil,
            "s" if numevil != 1 else ""))
예제 #50
0
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

    if targrole in Cursed:
        targrole = "wolf"
    elif targrole in Safe | Innocent:
        targrole = var.HIDDEN_ROLE
    elif targrole in Wolf:
        targrole = "wolf"

    evt = Event("see", {"role": targrole})
    evt.dispatch(var, wrapper.source, target)
    targrole = evt.data["role"]

    to_send = "oracle_success_not_wolf"
    if targrole == "wolf":
        to_send = "oracle_success_wolf"
    wrapper.send(messages[to_send].format(target))

    debuglog("{0} (oracle) SEE: {1} ({2}) (Wolf: {3})".format(wrapper.source, target, trole, "True" if targrole == "wolf" else "False"))

    SEEN.add(wrapper.source)
예제 #51
0
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"

    # used message keys (for grep): augur_success_blue, augur_success_red, augur_success_grey
    wrapper.send(messages["augur_success_" + aura].format(target))
    debuglog("{0} (augur) SEE: {1} ({2}) as {3} ({4} aura)".format(
        wrapper.source, target, trole, targrole, aura))

    SEEN.add(wrapper.source)
예제 #52
0
파일: wolf.py 프로젝트: random-nick/lykos
def on_transition_day(evt, var):
    # figure out wolf target
    found = defaultdict(int)
    nevt = Event("wolf_numkills", {"numkills": 1})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]
    for v in KILLS.values():
        for p in v:
            found[p] += 1
    for i in range(num_kills):
        maxc = 0
        dups = []
        for v, c in found.items():
            if c > maxc:
                maxc = c
                dups = [v]
            elif c == maxc:
                dups.append(v)
        if maxc and dups:
            target = random.choice(dups)
            evt.data["victims"].append(target)
            evt.data["bywolves"].add(target)
            evt.data["onlybywolves"].add(target)
            # special key to let us know to randomly select a wolf in case of retribution totem
            evt.data["killers"][target].append("@wolves")
            del found[target]

    # when monster is split, add protection to them if in onlybywolves
    # fallen angel will then remove that protection
    # TODO: when monster is split off
    if var.ROLES["fallen angel"]:
        for monster in get_all_players(("monster",)):
            if monster in evt.data["victims"]:
                evt.data["victims"].remove(monster)
                evt.data["bywolves"].discard(monster)
                evt.data["onlybywolves"].discard(monster)
예제 #53
0
def on_chk_decision_lynch3(evt, cli, var, voters):
    votee = evt.data["votee"]
    if votee in REVEALING:
        role = get_role(votee)
        rev_evt = Event("revealing_totem", {"role": role})
        rev_evt.dispatch(cli, var, votee)
        role = rev_evt.data["role"]
        # TODO: once amnesiac is split, roll this into the revealing_totem event
        if role == "amnesiac":
            role = var.AMNESIAC_ROLES[votee]
            change_role(users._get(votee), "amnesiac", role) # FIXME
            var.AMNESIACS.add(votee)
            pm(cli, votee, messages["totem_amnesia_clear"])
            # If wolfteam, don't bother giving list of wolves since night is about to start anyway
            # Existing wolves also know that someone just joined their team because revealing totem says what they are
            # If turncoat, set their initial starting side to "none" just in case game ends before they can set it themselves
            if role == "turncoat":
                var.TURNCOATS[votee] = ("none", -1)

        an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
        cli.msg(botconfig.CHANNEL, messages["totem_reveal"].format(votee, an, role))
        evt.data["votee"] = None
        evt.prevent_default = True
        evt.stop_processing = True
예제 #54
0
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, "kill", wrapper.source, target, frozenset({"detrimental"}))
    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)))
예제 #55
0
def on_transition_day(evt, var):
    # figure out wolf target
    found = defaultdict(int)
    nevt = Event("wolf_numkills", {"numkills": 1, "message": ""})
    nevt.dispatch(var)
    num_kills = nevt.data["numkills"]
    for v in KILLS.values():
        for p in v:
            found[p] += 1
    for i in range(num_kills):
        maxc = 0
        dups = []
        for v, c in found.items():
            if c > maxc:
                maxc = c
                dups = [v]
            elif c == maxc:
                dups.append(v)
        if maxc and dups:
            target = random.choice(dups)
            evt.data["victims"].append(target)
            # special key to let us know to randomly select a wolf in case of retribution totem
            evt.data["killers"][target].append("@wolves")
            del found[target]
예제 #56
0
def change_role(var,
                player,
                oldrole,
                newrole,
                *,
                inherit_from=None,
                message="new_role"):
    # in_wolfchat is filled as part of priority 4
    # if you wish to modify evt.data["role"], do so in priority 3 or sooner
    evt = Event("new_role", {
        "role": newrole,
        "messages": [],
        "in_wolfchat": False
    },
                inherit_from=inherit_from)
    evt.dispatch(var, player, oldrole)
    newrole = evt.data["role"]

    var.ROLES[oldrole].remove(player)
    var.ROLES[newrole].add(player)
    # only adjust MAIN_ROLES/FINAL_ROLES if we're changing the player's actual role
    if var.MAIN_ROLES[player] == oldrole:
        var.MAIN_ROLES[player] = newrole
        var.FINAL_ROLES[player.nick] = newrole

    sayrole = newrole
    if sayrole in var.HIDDEN_VILLAGERS:
        sayrole = "villager"
    elif sayrole in var.HIDDEN_ROLES:
        sayrole = var.DEFAULT_ROLE
    an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else ""

    player.send(messages[message].format(an, sayrole))
    player.send(*evt.data["messages"])

    return newrole
예제 #57
0
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
    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"]
    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)))
예제 #58
0
파일: traitor.py 프로젝트: bugmen0t/lykos
def on_update_stats3(evt, var, player, mainrole, revealrole, allroles):
    # if this is a night death and we know for sure that wolves (and only wolves)
    # killed, then that kill cannot be traitor as long as they're in wolfchat.
    wolfchat = get_wolfchat_roles(var)
    if evt.params.reason != "night_death":
        # a chained death, someone dying during day, or someone idling out
        # either way, traitor can die here
        return
    if "traitor" not in wolfchat:
        # wolves can kill traitor normally in this configuration
        return
    if "traitor" not in evt.data["possible"]:
        # not under consideration
        return
    if mainrole == "traitor":
        # definitely dying, so we shouldn't remove them from consideration
        # this may lead to info leaks, but info leaks are better than !stats just entirely breaking
        return
    if in_misdirection_scope(var, Wolf,
                             as_actor=True) or in_misdirection_scope(
                                 var, All - wolfchat, as_target=True):
        # luck/misdirection totems are in play, a wolf kill could have bounced to traitor anyway
        return

    if var.PHASE == "day" and var.GAMEPHASE == "night":
        mevt = Event("get_role_metadata", {})
        mevt.dispatch(var, "night_kills")
        nonwolf = 0
        total = 0
        for role, num in mevt.data.items():
            if role != "wolf":
                nonwolf += num
            total += num
        if nonwolf == 0:
            evt.data["possible"].discard("traitor")
            return
예제 #59
0
파일: shamans.py 프로젝트: svdermant/lykos
def on_transition_day_resolve6(evt, var, victims):
    for victim in victims:
        if victim in RETRIBUTION:
            killers = list(evt.data["killers"].get(victim, []))
            loser = None
            while killers:
                loser = random.choice(killers)
                if loser in evt.data["dead"] or victim is loser:
                    killers.remove(loser)
                    continue
                break
            if loser in evt.data["dead"] or victim is loser:
                loser = None
            ret_evt = Event("retribution_kill", {
                "target": loser,
                "message": []
            })
            ret_evt.dispatch(var, victim, loser)
            loser = ret_evt.data["target"]
            evt.data["message"][loser].extend(ret_evt.data["message"])
            if loser in evt.data["dead"] or victim is loser:
                loser = None
            if loser is not None:
                protected = try_protection(var, loser, victim,
                                           get_main_role(victim),
                                           "retribution_totem")
                if protected is not None:
                    channels.Main.send(*protected)
                    return

                evt.data["dead"].append(loser)
                to_send = "totem_death_no_reveal"
                if var.ROLE_REVEAL in ("on", "team"):
                    to_send = "totem_death"
                evt.data["message"][loser].append(messages[to_send].format(
                    victim, loser, get_reveal_role(loser)))
예제 #60
0
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
    for h, v in list(KILLS.items()):
        if v is user:
            h.send(messages["hunter_discard"])
            del KILLS[h]
        elif h is user:
            del KILLS[h]
    if death_triggers and "dullahan" in allroles:
        pl = evt.data["pl"]
        targets = TARGETS[user].intersection(users._get(x) for x in pl) # FIXME
        if targets:
            target = random.choice(list(targets))
            prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
            aevt = Event("assassinate", {"pl": evt.data["pl"], "target": target},
                    del_player=evt.params.del_player,
                    deadlist=evt.params.deadlist,
                    original=evt.params.original,
                    refresh_pl=evt.params.refresh_pl,
                    message_prefix="dullahan_die_",
                    source="dullahan",
                    killer=user.nick,
                    killer_mainrole=mainrole,
                    killer_allroles=allroles,
                    prots=prots)
            while len(prots) > 0:
                # an event can read the current active protection and cancel or redirect the assassination
                # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
                # so that it cannot be used again (if the protection is meant to be usable once-only)
                if not aevt.dispatch(user.client, var, user.nick, target.nick, prots[0]):
                    evt.data["pl"] = aevt.data["pl"]
                    if target is not aevt.data["target"]:
                        target = aevt.data["target"]
                        prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
                        aevt.params.prots = prots
                        continue
                    return
                prots.popleft()

            target = target.nick # FIXME
            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(user, target, an, role))
            else:
                channels.Main.send(messages["dullahan_die_success_noreveal"].format(user, target))
            debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(user, target, get_role(target)))
            evt.params.del_player(user.client, target, True, end_game=False, killer_role="dullahan", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
            evt.data["pl"] = evt.params.refresh_pl(pl)