コード例 #1
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
    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"]])
コード例 #2
0
ファイル: hooks.py プロジェクト: mweinelt/lykos
def end_who(cli, bot_server, bot_nick, target, rest):
    """Handle the end of WHO/WHOX responses from the server.

    Ordering and meaning of arguments for the end of a WHO/WHOX request:

    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 target the request was made against
    4 - A string containing some information; traditionally "End of /WHO list."

    This fires off the "who_end" event, and dispatches it with two
    arguments: The game state namespace and the channel or user the
    request was made to, or None if it could not be resolved.

    """

    try:
        target = channels.get(target)
    except KeyError:
        try:
            target = users._get(target)  # FIXME
        except KeyError:
            target = None
    else:
        if target._pending is not None:
            for name, params, args in target._pending:
                Event(name, params).dispatch(*args)
            target._pending = None

    Event("who_end", {}).dispatch(var, target)
コード例 #3
0
ファイル: harlot.py プロジェクト: asuralove/lykos
def hvisit(cli, nick, chan, rest):
    """Visit a player. You will die if you visit a wolf or a target of the wolves."""

    if VISITED.get(nick):
        pm(cli, nick, messages["harlot_already_visited"].format(VISITED[nick]))
        return
    victim = get_victim(cli, nick, re.split(" +", rest)[0], False, True)
    if not victim:
        return

    if nick == victim:
        pm(cli, nick, messages["harlot_not_self"])
        return

    evt = Event("targeted_command", {
        "target": victim,
        "misdirection": True,
        "exchange": True
    })
    evt.dispatch(cli, var, "visit", nick, victim, frozenset({"immediate"}))
    if evt.prevent_default:
        return
    victim = evt.data["target"]
    vrole = get_role(victim)

    VISITED[nick] = victim
    pm(cli, nick, messages["harlot_success"].format(victim))
    if nick != victim:
        pm(cli, victim, messages["harlot_success"].format(nick))
        revt = Event("harlot_visit", {})
        revt.dispatch(cli, var, nick, victim)

    debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, get_role(nick), victim,
                                                 vrole))
    chk_nightdone(cli)
コード例 #4
0
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

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

    target = evt.data["target"]

    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
    status.remove_lycanthropy(var, target)
    status.remove_disease(var, target)

    debuglog("{0} (doctor) IMMUNIZE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
コード例 #5
0
ファイル: succubus.py プロジェクト: Satssuki/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

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

    VISITED[wrapper.source] = target
    PASSED.discard(wrapper.source)

    if target not in get_all_players(("succubus",)):
        ENTRANCED.add(target)
        wrapper.send(messages["succubus_target_success"].format(target))
    else:
        wrapper.send(messages["harlot_success"].format(target))

    if wrapper.source is not target:
        if target not in get_all_players(("succubus",)):
            target.send(messages["notify_succubus_target"].format(wrapper.source))
        else:
            target.send(messages["harlot_success"].format(wrapper.source))

        revt = Event("succubus_visit", {})
        revt.dispatch(var, wrapper.source, target)

    debuglog("{0} (succubus) VISIT: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
コード例 #6
0
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)
            # Don't track players that quit before the game started
            if var.PHASE != "join":
                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)

        # give roles/modes an opportunity to adjust !stats now that all deaths have resolved
        evt = Event("reconfigure_stats", {"new": []})
        newstats = set()
        for rs in var.ROLE_STATS:
            d = Counter(dict(rs))
            evt.data["new"] = [d]
            evt.dispatch(var, d, "del_player")
            for v in evt.data["new"]:
                if min(v.values()) >= 0:
                    newstats.add(frozenset(v.items()))
        var.ROLE_STATS = frozenset(newstats)

        # 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)
コード例 #7
0
ファイル: wolf.py プロジェクト: random-nick/lykos
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")
コード例 #8
0
ファイル: succubus.py プロジェクト: Fudster/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

    evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": False})
    evt.dispatch(var, "visit", wrapper.source, target, frozenset({"detrimental", "immediate"}))
    if evt.prevent_default:
        return
    target = evt.data["target"]

    VISITED[wrapper.source] = target
    PASSED.discard(wrapper.source)

    if target not in get_all_players(("succubus",)):
        ENTRANCED.add(target)
        wrapper.send(messages["succubus_target_success"].format(target))
    else:
        wrapper.send(messages["harlot_success"].format(target))

    if wrapper.source is not target:
        if target not in get_all_players(("succubus",)):
            target.send(messages["notify_succubus_target"].format(wrapper.source))
        else:
            target.send(messages["harlot_success"].format(wrapper.source))

        revt = Event("succubus_visit", {})
        revt.dispatch(var, wrapper.source, target)

        # TODO: split these into assassin, hag, and alpha wolf when they are split off
        if users._get(var.TARGETED.get(target.nick), allow_none=True) in get_all_players(("succubus",)): # FIXME
            msg = messages["no_target_succubus"].format(var.TARGETED[target.nick])
            del var.TARGETED[target.nick]
            if target in get_all_players(("village drunk",)):
                victim = random.choice(list(get_all_players() - get_all_players(("succubus",)) - {target}))
                msg += messages["drunk_target"].format(victim)
                var.TARGETED[target.nick] = victim.nick
            target.send(msg)

        if target.nick in var.HEXED and users._get(var.LASTHEXED[target.nick]) in get_all_players(("succubus",)): # FIXME
            target.send(messages["retract_hex_succubus"].format(var.LASTHEXED[target.nick]))
            var.TOBESILENCED.remove(wrapper.source.nick)
            var.HEXED.remove(target.nick)
            del var.LASTHEXED[target.nick]
        if users._get(var.BITE_PREFERENCES.get(target.nick), allow_none=True) in get_all_players(("succubus",)): # FIXME
            target.send(messages["no_kill_succubus"].format(var.BITE_PREFERENCES[target.nick]))
            del var.BITE_PREFERENCES[target.nick]

    debuglog("{0} (succubus) VISIT: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
コード例 #9
0
ファイル: succubus.py プロジェクト: narakuphoenix/lykos
def hvisit(cli, nick, chan, rest):
    """Entrance a player, converting them to your team."""
    if VISITED.get(nick):
        pm(cli, nick, messages["succubus_already_visited"].format(VISITED[nick]))
        return
    victim = get_victim(cli, nick, re.split(" +",rest)[0], False, True)
    if not victim:
        return
    if nick == victim:
        pm(cli, nick, messages["succubus_not_self"])
        return
    evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": False})
    evt.dispatch(cli, var, "visit", nick, victim, frozenset({"detrimental", "immediate"}))
    if evt.prevent_default:
        return
    victim = evt.data["target"]
    vrole = get_role(victim)

    VISITED[nick] = victim
    if vrole != "succubus":
        ENTRANCED.add(victim)
        pm(cli, nick, messages["succubus_target_success"].format(victim))
    else:
        pm(cli, nick, messages["harlot_success"].format(victim))
    if nick != victim:
        if vrole != "succubus":
            pm(cli, victim, messages["notify_succubus_target"].format(nick))
        else:
            pm(cli, victim, messages["harlot_success"].format(nick))
        revt = Event("succubus_visit", {})
        revt.dispatch(cli, var, nick, victim)

        # TODO: split these into assassin, hag, and alpha wolf when they are split off
        if var.TARGETED.get(victim) in var.ROLES["succubus"]:
            msg = messages["no_target_succubus"].format(var.TARGETED[victim])
            del var.TARGETED[victim]
            if victim in var.ROLES["village drunk"]:
                target = random.choice(list(set(list_players()) - var.ROLES["succubus"] - {victim}))
                msg += messages["drunk_target"].format(target)
                var.TARGETED[victim] = target
            pm(cli, victim, nick)
        if victim in var.HEXED and var.LASTHEXED[victim] in var.ROLES["succubus"]:
            pm(cli, victim, messages["retract_hex_succubus"].format(var.LASTHEXED[victim]))
            var.TOBESILENCED.remove(nick)
            var.HEXED.remove(victim)
            del var.LASTHEXED[victim]
        if var.BITE_PREFERENCES.get(victim) in var.ROLES["succubus"]:
            pm(cli, victim, messages["no_kill_succubus"].format(var.BITE_PREFERENCES[victim]))
            del var.BITE_PREFERENCES[victim]

    debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, get_role(nick), victim, vrole))
    chk_nightdone(cli)
コード例 #10
0
def on_transition_day_resolve6(evt, cli, var, victim):
    # TODO: remove these checks once everything is split
    # right now they're needed because otherwise retribution may fire off when the target isn't actually dying
    # that will not be an issue once everything is using the event
    if victim in var.ROLES["harlot"] and var.HVISITED.get(
            victim) and victim not in evt.data["dead"] and victim in evt.data[
                "onlybywolves"]:
        return
    if evt.data["protected"].get(victim):
        return
    if victim in var.ROLES["lycan"] and victim in evt.data[
            "onlybywolves"] and victim not in var.IMMUNIZED:
        return
    # END checks to remove

    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 == loser:
                killers.remove(loser)
                continue
            break
        if loser in evt.data["dead"] or victim == loser:
            loser = None
        ret_evt = Event("retribution_kill", {"target": loser, "message": []})
        ret_evt.dispatch(cli, var, victim, loser)
        loser = ret_evt.data["target"]
        evt.data["message"].extend(ret_evt.data["message"])
        if loser in evt.data["dead"] or victim == loser:
            loser = None
        if loser is not None:
            prots = deque(var.ACTIVE_PROTECTIONS[loser])
            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)
                ret_evt = Event("retribution_totem", {"message": []})
                if not ret_evt.dispatch(cli, var, victim, loser, prots[0]):
                    evt.data["message"].extend(ret_evt.data["message"])
                    return
                prots.popleft()
            evt.data["dead"].append(loser)
            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(loser)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                evt.data["message"].append(messages["totem_death"].format(
                    victim, loser, an, role))
            else:
                evt.data["message"].append(
                    messages["totem_death_no_reveal"].format(victim, loser))
コード例 #11
0
ファイル: detective.py プロジェクト: Fudster/lykos
def investigate(cli, nick, chan, rest):
    """Investigate a player to determine their exact role."""
    if nick in INVESTIGATED:
        pm(cli, nick, messages["already_investigated"])
        return
    victim = get_victim(cli, nick, re.split(" +", rest)[0], False)
    if not victim:
        return

    if victim == nick:
        pm(cli, nick, messages["no_investigate_self"])
        return

    det = users._get(nick)  # FIXME
    target = users._get(victim)  # FIXME

    evt = Event("targeted_command", {
        "target": target,
        "misdirection": True,
        "exchange": True
    })
    evt.dispatch(var, "identify", det, target, frozenset({"info",
                                                          "immediate"}))
    if evt.prevent_default:
        return
    victim = evt.data["target"].nick
    vrole = get_role(victim)
    if vrole == "amnesiac":
        vrole = var.AMNESIAC_ROLES[victim]

    evt = Event("investigate", {"role": vrole})
    evt.dispatch(cli, var, nick, victim)
    vrole = evt.data["role"]

    INVESTIGATED.add(nick)
    pm(cli, nick, (messages["investigate_success"]).format(victim, vrole))
    debuglog("{0} ({1}) ID: {2} ({3})".format(nick, get_role(nick), victim,
                                              vrole))

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

        mass_privmsg(cli, list_players(wcroles),
                     messages["investigator_reveal"].format(nick))
        debuglog("{0} ({1}) PAPER DROP".format(nick, get_role(nick)))
コード例 #12
0
ファイル: shaman.py プロジェクト: the5thEmperor/lykos
def on_transition_night_end(evt, var):
    chances = var.CURRENT_GAMEMODE.TOTEM_CHANCES
    max_totems = sum(x["shaman"] for x in chances.values())
    ps = get_players()
    shamans = get_all_players(("shaman", ))
    for s in list(LASTGIVEN):
        if s not in shamans:
            del LASTGIVEN[s]

    shamans = list(shamans)
    random.shuffle(shamans)
    for shaman in shamans:
        pl = ps[:]
        random.shuffle(pl)
        for given in itertools.chain.from_iterable(LASTGIVEN[shaman].values()):
            if given in pl:
                pl.remove(given)

        event = Event("num_totems",
                      {"num": var.CURRENT_GAMEMODE.NUM_TOTEMS["shaman"]})
        event.dispatch(var, shaman, "shaman")
        num_totems = event.data["num"]

        totems = {}
        for i in range(num_totems):
            target = 0
            rand = random.random() * max_totems
            for t in chances:
                target += chances[t]["shaman"]
                if rand <= target:
                    if t in totems:
                        totems[t] += 1
                    else:
                        totems[t] = 1
                    break
        event = Event("totem_assignment", {"totems": totems})
        event.dispatch(var, shaman, "shaman")
        TOTEMS[shaman] = event.data["totems"]

        num_totems = sum(TOTEMS[shaman].values())
        if num_totems > 1:
            shaman.send(
                messages["shaman_notify_multiple_known"].format("shaman"))
        else:
            shaman.send(messages["shaman_notify"].format("shaman"))
        tmsg = totem_message(TOTEMS[shaman])
        for totem in TOTEMS[shaman]:
            tmsg += " " + messages[totem + "_totem"]
        shaman.send(tmsg)
        shaman.send(messages["players_list"].format(pl))
コード例 #13
0
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()
コード例 #14
0
ファイル: traitor.py プロジェクト: MishaCatskill/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
コード例 #15
0
ファイル: angel.py プロジェクト: TechnicianLP/lykos
def guard(cli, nick, chan, rest):
    """Guard a player, preventing them from being killed that night."""
    if nick in GUARDED:
        pm(cli, nick, messages["already_protecting"])
        return
    role = get_role(nick)
    self_in_list = role == "guardian angel" and var.GUARDIAN_ANGEL_CAN_GUARD_SELF
    victim = get_victim(cli, nick, re.split(" +",rest)[0], False, self_in_list)
    if not victim:
        return
    if (role == "bodyguard" or not var.GUARDIAN_ANGEL_CAN_GUARD_SELF) and victim == nick:
        pm(cli, nick, messages["cannot_guard_self"])
        return
    if role == "guardian angel" and LASTGUARDED.get(nick) == victim:
        pm(cli, nick, messages["guardian_target_another"].format(victim))
        return
    # self-guard ignores luck/misdirection/exchange totem
    evt = Event("targeted_command", {"target": victim, "misdirection": victim != nick, "exchange": victim != nick})
    if not evt.dispatch(cli, var, "guard", nick, victim, frozenset({"beneficial"})):
        return
    victim = evt.data["target"]
    GUARDED[nick] = victim
    LASTGUARDED[nick] = victim
    if victim == nick:
        pm(cli, nick, messages["guardian_guard_self"])
    else:
        pm(cli, nick, messages["protecting_target"].format(GUARDED[nick]))
        pm(cli, victim, messages["target_protected"])
    debuglog("{0} ({1}) GUARD: {2} ({3})".format(nick, role, victim, get_role(victim)))
    chk_nightdone(cli)
コード例 #16
0
ファイル: hooks.py プロジェクト: mweinelt/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))
コード例 #17
0
def add_lycanthropy(var, target, prefix="lycan"):
    """Effect the target with lycanthropy. Fire the add_lycanthropy event."""
    if target in LYCANTHROPES:
        return

    if target in get_players() and Event("add_lycanthropy", {}).dispatch(var, target):
        LYCANTHROPES[target] = prefix
コード例 #18
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)
コード例 #19
0
ファイル: vengefulghost.py プロジェクト: bspkrs/lykos
def vg_kill(cli, nick, chan, rest):
    """Take revenge on someone each night after you die."""
    if GHOSTS[nick][0] == "!":
        return

    victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
    if not victim:
        return

    if victim == nick:
        pm(cli, nick, messages["player_dead"])
        return

    wolves = list_players(var.WOLFTEAM_ROLES)
    if GHOSTS[nick] == "wolves" and victim not in wolves:
        pm(cli, nick, messages["vengeful_ghost_wolf"])
        return
    elif GHOSTS[nick] == "villagers" and victim in wolves:
        pm(cli, nick, messages["vengeful_ghost_villager"])
        return

    orig = victim
    evt = Event("targeted_command", {"target": victim, "misdirection": True, "exchange": False})
    evt.dispatch(cli, var, "kill", nick, victim, frozenset({"detrimental"}))
    if evt.prevent_default:
        return
    victim = evt.data["target"]

    KILLS[nick] = victim

    msg = messages["wolf_target"].format(orig)
    pm(cli, nick, messages["player"].format(msg))

    debuglog("{0} ({1}) KILL: {2} ({3})".format(nick, get_role(nick), victim, get_role(victim)))
    chk_nightdone(cli)
コード例 #20
0
ファイル: mystic.py プロジェクト: regayu/wwbot
def on_transition_night_end(evt, cli, var):
    # init with all roles that haven't been split yet
    special = set(
        list_players(("harlot", "priest", "prophet", "matchmaker", "doctor",
                      "hag", "sorcerer", "turncoat", "clone", "piper")))
    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"]

    for wolf in var.ROLES["wolf mystic"]:
        # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night
        # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals
        numvills = len(special & (pl - wolves - neutral))
        pm(
            cli, wolf, messages["wolf_mystic_info"].format(
                "are" if numvills != 1 else "is", numvills,
                "s" if numvills != 1 else ""))
    for mystic in var.ROLES["mystic"]:
        if mystic in var.PLAYERS and not is_user_simple(mystic):
            pm(cli, mystic, messages["mystic_notify"])
        else:
            pm(cli, mystic, messages["mystic_simple"])
        # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night
        numevil = len(wolves)
        pm(
            cli, mystic,
            messages["mystic_info"].format("are" if numevil != 1 else "is",
                                           numevil,
                                           "s" if numevil != 1 else ""))
コード例 #21
0
def on_chk_decision_lynch5(evt, cli, var, voters):
    votee = evt.data["votee"]
    if votee in DESPERATION:
        # Also kill the very last person to vote them, unless they voted themselves last in which case nobody else dies
        target = voters[-1]
        if target != votee:
            prots = deque(var.ACTIVE_PROTECTIONS[target])
            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)
                desp_evt = Event("desperation_totem", {})
                if not desp_evt.dispatch(cli, var, votee, target, prots[0]):
                    return
                prots.popleft()
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["totem_desperation"].format(
                    votee, target, an1, r1)
            else:
                tmsg = messages["totem_desperation_no_reveal"].format(
                    votee, target)
            cli.msg(botconfig.CHANNEL, tmsg)
            # we lie to this function so it doesn't devoice the player yet. instead, we'll let the call further down do it
            evt.data["deadlist"].append(target)
            better_deadlist = [users._get(p)
                               for p in evt.data["deadlist"]]  # FIXME
            target_user = users._get(target)  # FIXME
            evt.params.del_player(target_user,
                                  end_game=False,
                                  killer_role="shaman",
                                  deadlist=better_deadlist,
                                  ismain=False)
コード例 #22
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))
コード例 #23
0
def on_reconfigure_stats(evt, var, roleset, reason):
    from src.roles.helper.wolves import get_wolfchat_roles
    if reason != "howl" or not LYCANTHROPES 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)
コード例 #24
0
ファイル: hunter.py プロジェクト: bspkrs/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)
コード例 #25
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
コード例 #26
0
ファイル: traitor.py プロジェクト: svdermant/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
コード例 #27
0
ファイル: mystic.py プロジェクト: regayu/wwbot
def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
    special = set(
        list_players(("harlot", "priest", "prophet", "matchmaker", "doctor",
                      "hag", "sorcerer", "turncoat", "clone", "piper")))
    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 ""))
コード例 #28
0
ファイル: hooks.py プロジェクト: svdermant/lykos
def end_who(cli, bot_server, bot_nick, target, rest):
    """Handle the end of WHO/WHOX responses from the server.

    Ordering and meaning of arguments for the end of a WHO/WHOX request:

    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 target the request was made against
    4 - A string containing some information; traditionally "End of /WHO list."

    This fires off the "who_end" event, and dispatches it with one
    argument: The channel or user the request was made to, or None
    if it could not be resolved.

    """

    try:
        target = channels.get(target)
    except KeyError:
        try:
            target = users.get(target)
        except KeyError:
            target = None
    else:
        target.dispatch_queue()

    old = _who_old.get(target.name, target)
    _who_old.clear()
    Event("who_end", {}, old=old).dispatch(target)
コード例 #29
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, wrapper.source, target)
    if evt.prevent_default:
        return

    target = evt.data["target"]

    KILLS[wrapper.source] = target
    HUNTERS.add(wrapper.source)
    PASSED.discard(wrapper.source)

    wrapper.pm(messages["player_kill"].format(orig))

    debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target,
                                                   get_main_role(target)))
コード例 #30
0
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