Ejemplo n.º 1
0
def on_retribution_kill(evt, cli, var, victim, orig_target):
    t = evt.data["target"]
    if users._get(t) in GHOSTS:
        drivenoff[t] = GHOSTS[users._get(t)]
        GHOSTS[users._get(t)] = "!" + GHOSTS[users._get(t)]
        evt.data["message"].append(messages["totem_banish"].format(victim, t))
        evt.data["target"] = None
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
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

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

    # self-guard ignores luck/misdirection/exchange totem
    evt = Event("targeted_command", {"target": target, "misdirection": (angel is not target), "exchange": (angel is not target)})
    if not evt.dispatch(var, angel, target):
        return
    victim = evt.data["target"].nick
    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)))
Ejemplo n.º 4
0
def on_transition_day2(evt, var):
    for k, d in DEATH.items():
        shaman = users._get(k)  # FIXME
        target = users._get(d)  # FIXME
        evt.data["victims"].append(target)
        evt.data["onlybywolves"].discard(target)
        evt.data["killers"][target].append(shaman)
Ejemplo n.º 5
0
def on_get_participant_role(evt, var, nick):
    if users._get(nick) in GHOSTS: # FIXME
        if nick in drivenoff:
            against = drivenoff[nick]
        else:
            against = GHOSTS[users._get(nick)]
        if against == "villagers":
            evt.data["role"] = "wolf"
        elif against == "wolves":
            evt.data["role"] = "villager"
Ejemplo n.º 6
0
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)))
Ejemplo n.º 7
0
def on_transition_day(evt, var):
    for k, v in list(KILLS.items()):
        killer = users._get(k)  # FIXME
        victim = users._get(v)  # FIXME
        evt.data["victims"].append(victim)
        # even though doomsayer is a wolf, remove from onlybywolves since
        # that particular item indicates that they were the target of a wolf !kill.
        # If doomsayer doesn't remove this, roles such as harlot or monster will not
        # die if they are the target of a doomsayer !see that ends up killing the target.
        evt.data["onlybywolves"].discard(victim)
        evt.data["killers"][victim].append(killer)
Ejemplo n.º 8
0
def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
    for k in set(KILLS):
        if k.nick == actor or k.nick == nick:
            del KILLS[k]

    for k in set(TARGETS):
        if actor_role == "dullahan" and nick_role != "dullahan" and k.nick == actor:
            TARGETS[users._get(nick)] = TARGETS.pop(k) - {users._get(nick)
                                                          }  # FIXME
        elif nick_role == "dullahan" and actor_role != "dullahan" and k.nick == nick:
            TARGET[users._get(actor)] = TARGETS.pop(k) - {users._get(actor)
                                                          }  # FIXME
Ejemplo n.º 9
0
def on_transition_day(evt, var):
    for k, v in list(KILLS.items()):
        killer = users._get(k)  # FIXME
        victim = users._get(v)  # FIXME
        evt.data["victims"].append(victim)
        evt.data["onlybywolves"].discard(victim)
        evt.data["killers"][victim].append(killer)
        # important, otherwise our del_player listener lets hunter kill again
        del KILLS[k]

        if get_main_role(victim) not in var.WOLF_ROLES | var.WIN_STEALER_ROLES:
            var.DYING.add(killer)
Ejemplo n.º 10
0
def totem(
    cli,
    nick,
    chan,
    rest,
    prefix="You"
):  # XXX: The transition_day_begin event needs updating alongside this
    """Give a totem to a player."""
    victim = get_victim(cli, nick, re.split(" +", rest)[0], False, True)
    if not victim:
        return
    if LASTGIVEN.get(nick) == victim:
        pm(cli, nick, messages["shaman_no_target_twice"].format(victim))
        return

    original_victim = victim
    role = get_role(
        nick
    )  # FIXME: this is bad, check if nick is in var.ROLES[thingy] instead once split
    totem = ""
    if role != "crazed shaman":
        totem = " of " + TOTEMS[nick]

    tags = set()
    if role != "crazed shaman" and TOTEMS[nick] in var.BENEFICIAL_TOTEMS:
        tags.add("beneficial")

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

    evt = Event("targeted_command", {
        "target": target,
        "misdirection": True,
        "exchange": True
    },
                action="give a totem{0} to".format(totem))
    evt.dispatch(var, "totem", shaman, target, frozenset(tags))
    if evt.prevent_default:
        return
    victim = evt.data["target"].nick
    victimrole = get_role(victim)

    pm(cli, nick, messages["shaman_success"].format(prefix, totem,
                                                    original_victim))
    if role == "wolf shaman":
        relay_wolfchat_command(cli,
                               nick,
                               messages["shaman_wolfchat"].format(
                                   nick, original_victim), ("wolf shaman", ),
                               is_wolf_command=True)
    SHAMANS[nick] = (victim, original_victim)
    debuglog("{0} ({1}) TOTEM: {2} ({3})".format(nick, role, victim,
                                                 TOTEMS[nick]))
Ejemplo n.º 11
0
def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
    for h, v in list(KILLS.items()):
        if v.nick == nick:
            h.send(messages["hunter_discard"])
            del KILLS[h]
        elif h.nick == nick:
            del KILLS[h]
    if death_triggers and nickrole == "dullahan":
        pl = evt.data["pl"]
        targets = TARGETS[users._get(nick)].intersection(
            users._get(x) for x in pl)  # FIXME
        if targets:
            target = random.choice(list(targets)).nick
            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_",
                         nickrole=nickrole,
                         nicktpls=nicktpls,
                         prots=prots)
            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)
Ejemplo n.º 12
0
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)))
Ejemplo n.º 13
0
def on_exchange_roles(evt, var, actor, target, actor_role, target_role):
    if actor_role == "harlot":
        if actor.nick in VISITED:
            if VISITED[actor.nick] is not None:
                visited = users._get(VISITED[actor.nick])  # FIXME
                visited.send(messages["harlot_disappeared"].format(actor))
            del VISITED[actor.nick]
    if target_role == "harlot":
        if target.nick in VISITED:
            if VISITED[target.nick] is not None:
                visited = users._get(VISITED[target.nick])  # FIXME
                visited.send(messages["harlot_disappeared"].format(target))
            del VISITED[target.nick]
Ejemplo n.º 14
0
def on_exchange(evt, var, actor, target, actor_role, target_role):
    if actor_role in ("bodyguard", "guardian angel"):
        if actor.nick in GUARDED:
            guarded = users._get(GUARDED.pop(actor.nick)) # FIXME
            guarded.send(messages["protector disappeared"])
        if actor.nick in LASTGUARDED:
            del LASTGUARDED[actor.nick]
    if target_role in ("bodyguard", "guardian angel"):
        if target.nick in GUARDED:
            guarded = users._get(GUARDED.pop(target.nick)) # FIXME
            guarded.send(messages["protector disappeared"])
        if target.nick in LASTGUARDED:
            del LASTGUARDED[target.nick]
Ejemplo n.º 15
0
def mass_privmsg(cli, targets, msg, notice=False, privmsg=False):
    from src.users import _get
    targs = [_get(t) for t in targets]
    for user in targs:
        user.queue_message(msg)
    if targs:
        user.send_messages()
Ejemplo n.º 16
0
def on_doctor_immunize(evt, var, doctor, target):
    user = users._get(target)  # FIXME
    if user in SICK.values():
        for n, v in list(SICK.items()):
            if v is user:
                del SICK[n]
        evt.data["message"] = "not_sick"
Ejemplo n.º 17
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.nick, "misdirection": True, "exchange": False})
    evt.dispatch(wrapper.source.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
    if evt.prevent_default:
        return
    target = users._get(evt.data["target"]) # FIXME

    KILLS[wrapper.source] = target

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

    debuglog("{0} (vengeful ghost) KILL: {1} ({2})".format(wrapper.source.nick, target, get_main_role(target)))
    chk_nightdone(wrapper.source.client)
Ejemplo n.º 18
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
Ejemplo n.º 19
0
def on_revealroles(evt, var, wrapper, nickname, role):
    if role == "mad scientist":
        pl = get_players()
        target1, target2 = _get_targets(var, pl, users._get(nickname))  # FIXME
        evt.data["special_case"].append(
            messages["mad_scientist_revealroles_targets"].format(
                target1, target2))
Ejemplo n.º 20
0
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)
Ejemplo n.º 21
0
def on_chk_decision(evt, cli, var, force):
    for votee, voters in evt.data["votelist"].items():
        if users._get(votee) in get_all_players(("succubus",)): # FIXME
            for vtr in ENTRANCED:
                if vtr.nick in voters:
                    evt.data["numvotes"][votee] -= evt.data["weights"][votee][vtr.nick]
                    evt.data["weights"][votee][vtr.nick] = 0
Ejemplo n.º 22
0
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))
Ejemplo n.º 23
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_role(target.nick)))

    chk_nightdone(wrapper.client)
Ejemplo n.º 24
0
def on_transition_day6(evt, cli, var):
    for k, d in list(KILLS.items()):
        if GHOSTS[users._get(k)] == "villagers" and k in evt.data["killers"][d]:
            evt.data["killers"][d].remove(k)
            evt.data["killers"][d].insert(0, k)
        # important, otherwise our del_player listener messages the vg
        del KILLS[k]
Ejemplo n.º 25
0
def on_chghost(cli, rawnick, ident, host):
    """Handle a user changing host without a quit.

    Ordering and meaning of arguments for CHGHOST:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user switching
    2 - The new ident for the user (or same if unchanged)
    3 - The new host for the user (or same if unchanged)

    """

    user = users._get(rawnick)  # FIXME
    new = users._add(cli,
                     nick=user.nick,
                     ident=ident,
                     host=host,
                     realname=user.realname,
                     account=user.account)  # FIXME

    if user is not new:
        new.channels = user.channels.copy()
        new.timestamp = user.timestamp  # We lie, but it's ok
        for chan in set(user.channels):
            chan.remove_user(user)
            chan.users.add(new)
        user.swap(new)
Ejemplo n.º 26
0
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))
Ejemplo n.º 27
0
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)
Ejemplo n.º 28
0
def see(cli, nick, chan, rest):
    """Use your paranormal senses to determine a player's doom."""
    role = get_role(nick)
    if nick in SEEN:
        pm(cli, nick, messages["seer_fail"])
        return
    victim = get_victim(cli, nick, re.split(" +", rest)[0], False)
    if not victim:
        return

    if victim == nick:
        pm(cli, nick, messages["no_see_self"])
        return
    if in_wolflist(nick, victim):
        pm(cli, nick, messages["no_see_wolf"])
        return

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

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

    mode, mapping = random.choice(_mappings)
    pm(cli, nick, messages["doomsayer_{0}".format(mode)].format(victim))
    if mode != "sick" or nick not in var.IMMUNIZED:
        mapping[nick] = victim

    debuglog("{0} ({1}) SEE: {2} ({3}) - {4}".format(nick, role, victim,
                                                     victimrole, mode.upper()))
    relay_wolfchat_command(cli,
                           nick,
                           messages["doomsayer_wolfchat"].format(nick, victim),
                           ("doomsayer", ),
                           is_wolf_command=True)

    SEEN.add(nick)
Ejemplo n.º 29
0
def on_succubus_visit(evt, var, succubus, target):
    if (users._get(SHAMANS.get(target.nick, (None, None))[1], allow_none=True)
            in get_all_players(("succubus", )) and  # FIXME
        (get_main_role(target) == "crazed shaman"
         or TOTEMS[target.nick] not in var.BENEFICIAL_TOTEMS)):
        target.send(messages["retract_totem_succubus"].format(
            SHAMANS[target.nick][1]))
        del SHAMANS[target.nick]
Ejemplo n.º 30
0
def on_get_role_metadata(evt, var, kind):
    if kind == "night_kills":
        # hunters is the set of all hunters that have not killed in a *previous* night
        # (if they're in both HUNTERS and KILLS, then they killed tonight and should be counted)
        hunters = ({users._get(h)
                    for h in var.ROLES["hunter"]} - HUNTERS) | set(
                        KILLS.keys())  # FIXME
        evt.data["hunter"] = len(hunters)
Ejemplo n.º 31
0
def on_chk_decision_lynch(evt, cli, var, voters):
    votee = evt.data["votee"]
    if users._get(votee) in var.ROLES[
            "mayor"] and votee not in REVEALED_MAYORS:  # FIXME
        cli.msg(botconfig.CHANNEL, messages["mayor_reveal"].format(votee))
        REVEALED_MAYORS.add(votee)
        evt.data["votee"] = None
        evt.prevent_default = True
        evt.stop_processing = True
Ejemplo n.º 32
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[users._get(dull)] = set() # FIXME
        dull_targets = Event("dullahan_targets", {"targets": TARGETS}) # support sleepy
        dull_targets.dispatch(cli, var, {users._get(x) for x in var.ROLES["dullahan"]}, max_targets) # FIXME

        players = [users._get(x) for x in pl] # FIXME

        for dull, ts in TARGETS.items():
            ps = players[:]
            ps.remove(dull)
            while len(ts) < max_targets:
                target = random.choice(ps)
                ps.remove(target)
                ts.add(target)
Ejemplo n.º 33
0
def kicked_from_chan(cli, rawnick, chan, target, reason):
    """Handle a user being kicked from a channel.

    Ordering and meaning of arguments for a channel KICK:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user performing the kick
    2 - The channel the kick was performed on
    3 - The target of the kick
    4 - The reason given for the kick (always present)

    """

    ch = channels.add(chan, cli)
    actor = users._get(rawnick, allow_none=True) # FIXME
    user = users._get(target) # FIXME
    Event("chan_kick", {}).dispatch(var, ch, actor, user, reason)

    if user is users.Bot:
        ch._clear()
    else:
        ch.remove_user(user)
Ejemplo n.º 34
0
def on_nick_change(cli, old_rawnick, nick):
    """Handle a user changing nicks, which may be the bot itself.

    Ordering and meaning of arguments for a NICK change:

    0 - The IRCClient instance (like everywhere else)
    1 - The old (raw) nickname the user changed from
    2 - The new nickname the user changed to

    """

    user = users._get(old_rawnick, allow_bot=True) # FIXME
    user.nick = nick

    Event("nick_change", {}).dispatch(var, user, old_rawnick)
Ejemplo n.º 35
0
def on_account_change(cli, rawnick, account):
    """Handle a user changing accounts, if enabled.

    Ordering and meaning of arguments for an ACCOUNT change:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user changing accounts
    2 - The account the user changed to

    We don't see our own account changes, so be careful!

    """

    user = users._get(rawnick) # FIXME
    user.account = account # We don't pass it to add(), since we want to grab the existing one (if any)

    Event("account_change", {}).dispatch(var, user)
Ejemplo n.º 36
0
def on_quit(cli, rawnick, reason):
    """Handle a user quitting the IRC server.

    Ordering and meaning of arguments for a server QUIT:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user quitting
    2 - The reason for the quit (always present)

    """

    user = users._get(rawnick, allow_bot=True) # FIXME
    Event("server_quit", {}).dispatch(var, user, reason)

    for chan in set(user.channels):
        if user is users.Bot:
            chan._clear()
        else:
            chan.remove_user(user)
Ejemplo n.º 37
0
def on_chghost(cli, rawnick, ident, host):
    """Handle a user changing host without a quit.

    Ordering and meaning of arguments for CHGHOST:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user switching
    2 - The new ident for the user (or same if unchanged)
    3 - The new host for the user (or same if unchanged)

    """

    user = users._get(rawnick) # FIXME
    new = users._add(cli, nick=user.nick, ident=ident, host=host, realname=user.realname, account=user.account) # FIXME

    if user is not new:
        new.channels = user.channels.copy()
        new.timestamp = user.timestamp # We lie, but it's ok
        for chan in set(user.channels):
            chan.remove_user(user)
            chan.users.add(new)
        user.swap(new)
Ejemplo n.º 38
0
def part_chan(cli, rawnick, chan, reason=""):
    """Handle a user leaving a channel, which may be the bot itself.

    Ordering and meaning of arguments for a channel PART:

    0 - The IRCClient instance (like everywhere else)
    1 - The raw nick (nick!ident@host) of the user leaving the channel
    2 - The channel being left

    The following argument may or may not be present:

    3 - The reason the user gave for parting (if any)

    """

    ch = channels.add(chan, cli)
    user = users._get(rawnick) # FIXME
    Event("chan_part", {}).dispatch(var, ch, user, reason)

    if user is users.Bot: # oh snap! we're no longer in the channel!
        ch._clear()
    else:
        ch.remove_user(user)
Ejemplo n.º 39
0
def get_role(p):
    # TODO DEPRECATED: replace with get_main_role(user)
    from src import users
    from src.functions import get_main_role
    return get_main_role(users._get(p))
Ejemplo n.º 40
0
def pm(cli, target, message):
    from src.users import _get
    user = _get(target)
    user.send(message)
Ejemplo n.º 41
0
def on_privmsg(cli, rawnick, chan, msg, *, notice=False, force_role=None):
    if notice and "!" not in rawnick or not rawnick: # server notice; we don't care about those
        return

    user = users._get(rawnick, allow_none=True) # FIXME

    ch = chan.lstrip("".join(hooks.Features["PREFIX"]))

    if users.equals(chan, users.Bot.nick): # PM
        target = users.Bot
    else:
        target = channels.get(ch, allow_none=True)

    if user is None or target is None:
        return

    wrapper = MessageDispatcher(user, target)

    if wrapper.public and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
        return

    if (notice and ((wrapper.public and not botconfig.ALLOW_NOTICE_COMMANDS) or
                    (wrapper.private and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
        return  # not allowed in settings

    if force_role is None: # if force_role isn't None, that indicates recursion; don't fire these off twice
        for fn in decorators.COMMANDS[""]:
            fn.caller(cli, rawnick, ch, msg)

    parts = msg.split(sep=" ", maxsplit=1)
    key = parts[0].lower()
    if len(parts) > 1:
        message = parts[1].lstrip()
    else:
        message = ""

    if wrapper.public and not key.startswith(botconfig.CMD_CHAR):
        return # channel message but no prefix; ignore

    if key.startswith(botconfig.CMD_CHAR):
        key = key[len(botconfig.CMD_CHAR):]

    if not key: # empty key ("") already handled above
        return

    # Don't change this into decorators.COMMANDS[key] even though it's a defaultdict,
    # as we don't want to insert bogus command keys into the dict.
    cmds = []
    phase = var.PHASE
    if user in get_participants():
        roles = get_all_roles(user)
        # A user can be a participant but not have a role, for example, dead vengeful ghost
        has_roles = len(roles) != 0
        if force_role is not None:
            roles &= {force_role} # only fire off role commands for the forced role

        common_roles = set(roles) # roles shared by every eligible role command
        have_role_cmd = False
        for fn in decorators.COMMANDS.get(key, []):
            if not fn.roles:
                cmds.append(fn)
                continue
            if roles.intersection(fn.roles):
                have_role_cmd = True
                cmds.append(fn)
                common_roles.intersection_update(fn.roles)

        if force_role is not None and not have_role_cmd:
            # Trying to force a non-role command with a role.
            # We allow non-role commands to execute if a role is forced if a role
            # command is also executed, as this would allow (for example) a bot admin
            # to add extra effects to all "kill" commands without needing to continually
            # update the list of roles which can use "kill". However, we don't want to
            # allow things like "wolf pstats" because that just doesn't make sense.
            return

        if has_roles and not common_roles:
            # getting here means that at least one of the role_cmds is disjoint
            # from the others. For example, augur see vs seer see when a bare see
            # is executed. In this event, display a helpful error message instructing
            # the user to resolve the ambiguity.
            common_roles = set(roles)
            info = [0,0]
            for fn in cmds:
                fn_roles = roles.intersection(fn.roles)
                if not fn_roles:
                    continue
                for role1 in common_roles:
                    info[0] = role1
                    break
                for role2 in fn_roles:
                    info[1] = role2
                    break
                common_roles &= fn_roles
                if not common_roles:
                    break
            wrapper.pm(messages["ambiguous_command"].format(key, info[0], info[1]))
            return
    elif force_role is None:
        cmds = decorators.COMMANDS.get(key, [])

    for fn in cmds:
        if phase == var.PHASE:
            # FIXME: pass in var, wrapper, message instead of cli, rawnick, chan, message
            fn.caller(cli, rawnick, ch, message)
Ejemplo n.º 42
0
def relay_wolfchat_command(cli, nick, message, roles, is_wolf_command=False, is_kill_command=False):
    from src.roles.helper.wolves import send_wolfchat_message
    from src import users
    role = "wolf" if is_wolf_command else None
    command = "kill" if is_kill_command else None
    send_wolfchat_message(var, users._get(nick), message, roles, role=role, command=command)
Ejemplo n.º 43
0
def is_admin(nick, ident=None, host=None, acc=None):
    from src.users import _get
    user = _get(nick=nick, ident=ident, host=host, account=acc)
    return user.is_admin()
Ejemplo n.º 44
0
    def update_modes(self, actor, mode, targets):
        """Update the channel's mode registry with the new modes.

        This is called whenever a MODE event is received. All of the
        modes are kept up-to-date in the channel, even if we don't need
        it. For instance, banlists are updated properly when the bot
        receives them. We don't need all the mode information, but it's
        better to have everything stored than only some parts.

        """

        set_time = int(time.time()) # for list modes timestamp
        list_modes, all_set, only_set, no_set = Features["CHANMODES"]
        status_modes = Features["PREFIX"].values()

        i = 0
        for c in mode:
            if c in ("+", "-"):
                prefix = c
                continue

            if prefix == "+":
                if c in status_modes: # op/voice status; keep it here and update the user's registry too
                    if c not in self.modes:
                        self.modes[c] = set()
                    user = users._get(targets[i], allow_bot=True) # FIXME
                    self.modes[c].add(user)
                    user.channels[self].add(c)
                    if user in var.OLD_MODES:
                        var.OLD_MODES[user].discard(c)
                    i += 1

                elif c in list_modes: # stuff like bans, quiets, and ban and invite exempts
                    if c not in self.modes:
                        self.modes[c] = {}
                    self.modes[c][targets[i]] = ((actor.rawnick if actor is not None else None), set_time)
                    i += 1

                else:
                    if c in no_set: # everything else; e.g. +m, +i, +f, etc.
                        targ = None
                    else:
                        targ = targets[i]
                        i += 1
                    if c in only_set and targ.isdigit(): # +l/+j
                        targ = int(targ)
                    self.modes[c] = targ

            else:
                if c in status_modes:
                    if c in self.modes:
                        user = users._get(targets[i], allow_bot=True) # FIXME
                        self.modes[c].discard(user)
                        user.channels[self].discard(c)
                        if not self.modes[c]:
                            del self.modes[c]
                    i += 1

                elif c in list_modes:
                    if c in self.modes:
                        self.modes[c].pop(targets[i], None)
                        if not self.modes[c]:
                            del self.modes[c]
                    i += 1

                else:
                    if c in all_set:
                        i += 1 # -k needs a target, but we don't care about it
                    del self.modes[c]

        if "k" in mode:
            self._key = self.modes.get("k", "")
Ejemplo n.º 45
0
def in_wolflist(nick, who):
    from src.roles.helper.wolves import is_known_wolf_ally
    from src import users
    return is_known_wolf_ally(var, users._get(nick), users._get(who))