Esempio n. 1
0
    def __init__(self, arg=""):
        super().__init__(arg)
        self.LIMIT_ABSTAIN = False
        self.DEFAULT_ROLE = "shaman"
        # If you add non-wolfteam, non-shaman roles, be sure to update update_stats to account for it!
        # otherwise !stats will break if they turn into VG.
        self.ROLE_GUIDE = {
            6: ["wolf shaman"],
            10: ["wolf shaman(2)"],
            15: ["wolf shaman(3)"],
            20: ["wolf shaman(4)"]
            }
        self.EVENTS = {
            "transition_night_end": EventListener(self.on_transition_night_end, priority=1),
            "wolf_numkills": EventListener(self.on_wolf_numkills),
            "totem_assignment": EventListener(self.on_totem_assignment),
            "transition_day_begin": EventListener(self.on_transition_day_begin, priority=8),
            "transition_day_resolve_end": EventListener(self.on_transition_day_resolve_end, priority=2),
            "del_player": EventListener(self.on_del_player),
            "apply_totem": EventListener(self.on_apply_totem),
            "lynch": EventListener(self.on_lynch),
            "chk_win": EventListener(self.on_chk_win),
            "revealroles_role": EventListener(self.on_revealroles_role),
            "update_stats": EventListener(self.on_update_stats),
            "begin_night": EventListener(self.on_begin_night)
        }

        self.TOTEM_CHANCES = {totem: {} for totem in self.DEFAULT_TOTEM_CHANCES}
        self.set_default_totem_chances()
        for totem, roles in self.TOTEM_CHANCES.items():
            for role in roles:
                self.TOTEM_CHANCES[totem][role] = 0
        # custom totems
        self.TOTEM_CHANCES["sustenance"] = {"shaman": 12, "wolf shaman": 0, "crazed shaman": 0}
        self.TOTEM_CHANCES["hunger"] = {"shaman": 0, "wolf shaman": 6, "crazed shaman": 0}
        # extra shaman totems
        self.TOTEM_CHANCES["revealing"]["shaman"] = 4
        self.TOTEM_CHANCES["death"]["shaman"] = 1
        self.TOTEM_CHANCES["pacifism"]["shaman"] = 2
        self.TOTEM_CHANCES["silence"]["shaman"] = 1
        # extra WS totems: note that each WS automatically gets a hunger totem in addition to this in phase 1
        self.TOTEM_CHANCES["death"]["wolf shaman"] = 2
        self.TOTEM_CHANCES["revealing"]["wolf shaman"] = 2
        self.TOTEM_CHANCES["luck"]["wolf shaman"] = 4
        self.TOTEM_CHANCES["silence"]["wolf shaman"] = 1
        self.TOTEM_CHANCES["pacifism"]["wolf shaman"] = 2
        self.TOTEM_CHANCES["impatience"]["wolf shaman"] = 3

        self.hunger_levels = DefaultUserDict(int)
        self.totem_tracking = defaultdict(int) # no need to make a user container, this is only non-empty a very short time
        self.phase = 1
        self.max_nights = 7
        self.village_hunger = 0
        self.village_hunger_percent_base = 0.3
        self.village_hunger_percent_adj = 0.03
        self.village_starve = 0
        self.max_village_starve = 3
        self.num_retribution = 0
        self.saved_messages = {} # type: Dict[str, str]
        self.feed_command = None
Esempio n. 2
0
def add_protection(var, target, protector, protector_role, scope=All):
    """Add a protection to the target affecting the relevant scope."""
    if target not in get_players():
        return

    if target not in PROTECTIONS:
        PROTECTIONS[target] = DefaultUserDict(list)

    prot_entry = (scope, protector_role)
    PROTECTIONS[target][protector].append(prot_entry)
Esempio n. 3
0
from src.containers import DefaultUserDict
from src.decorators import event_listener
from src.functions import get_players
from src.events import Event

__all__ = ["add_lynch_immunity", "try_lynch_immunity"]

IMMUNITY = DefaultUserDict(set)  # type: UserDict[User, set]


def add_lynch_immunity(var, user, reason):
    """Make user immune to lynching for one day."""
    if user not in get_players():
        return
    IMMUNITY[user].add(reason)


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


@event_listener("revealroles")
def on_revealroles(evt, var, wrapper):
    if IMMUNITY:
        evt.data["output"].append("\u0002lynch immunity\u0002: {0}".format(
Esempio n. 4
0
 def ulf():
     # Factory method to create a DefaultUserDict[*, UserList]
     # this can be passed into a DefaultUserDict constructor so we can make nested defaultdicts easily
     return DefaultUserDict(UserList)
Esempio n. 5
0
def setup_variables(rolename, *, knows_totem):
    """Setup role variables and shared events."""
    def ulf():
        # Factory method to create a DefaultUserDict[*, UserList]
        # this can be passed into a DefaultUserDict constructor so we can make nested defaultdicts easily
        return DefaultUserDict(UserList)

    TOTEMS = DefaultUserDict(
        dict)  # type: DefaultUserDict[users.User, Dict[str, int]]
    LASTGIVEN = DefaultUserDict(
        ulf
    )  # type: DefaultUserDict[users.User, DefaultUserDict[str, UserList]]
    SHAMANS = DefaultUserDict(
        ulf
    )  # type: DefaultUserDict[users.User, DefaultUserDict[str, UserList]]
    RETARGET = DefaultUserDict(
        UserDict
    )  # type: DefaultUserDict[users.User, UserDict[users.User, users.User]]
    _rolestate[rolename] = {
        "TOTEMS": TOTEMS,
        "LASTGIVEN": LASTGIVEN,
        "SHAMANS": SHAMANS,
        "RETARGET": RETARGET
    }

    @event_listener("reset",
                    listener_id="shamans.<{}>.on_reset".format(rolename))
    def on_reset(evt, var):
        TOTEMS.clear()
        LASTGIVEN.clear()
        SHAMANS.clear()
        RETARGET.clear()

    @event_listener("begin_day",
                    listener_id="shamans.<{}>.on_begin_day".format(rolename))
    def on_begin_day(evt, var):
        SHAMANS.clear()
        RETARGET.clear()

    @event_listener(
        "revealroles_role",
        listener_id="shamans.<{}>.revealroles_role".format(rolename))
    def on_revealroles(evt, var, user, role):
        if role == rolename and user in TOTEMS:
            if var.PHASE == "night":
                evt.data["special_case"].append(
                    messages["shaman_revealroles_night"].format(
                        (messages["shaman_revealroles_night_totem"].format(
                            num, totem)
                         for num, totem in TOTEMS[user].items()),
                        sum(TOTEMS[user].values())))
            elif user in LASTGIVEN and LASTGIVEN[user]:
                given = []
                for totem, recips in LASTGIVEN[user].items():
                    for recip in recips:
                        given.append(
                            messages["shaman_revealroles_day_totem"].format(
                                totem, recip))
                evt.data["special_case"].append(
                    messages["shaman_revealroles_day"].format(given))

    @event_listener(
        "transition_day_begin",
        priority=7,
        listener_id="shamans.<{}>.transition_day_begin".format(rolename))
    def on_transition_day_begin2(evt, var):
        LASTGIVEN.clear()
        for shaman, given in SHAMANS.items():
            for totem, targets in given.items():
                for target in targets:
                    victim = RETARGET[shaman].get(target, target)
                    if not victim:
                        continue
                    if totem == "death":  # this totem stacks
                        if shaman not in DEATH:
                            DEATH[shaman] = UserList()
                        DEATH[shaman].append(victim)
                    elif totem == "protection":  # this totem stacks
                        PROTECTION.append(victim)
                    elif totem == "revealing":
                        REVEALING.add(victim)
                    elif totem == "narcolepsy":
                        NARCOLEPSY.add(victim)
                    elif totem == "silence":
                        SILENCE.add(victim)
                    elif totem == "desperation":
                        DESPERATION.add(victim)
                    elif totem == "impatience":  # this totem stacks
                        IMPATIENCE.append(victim)
                    elif totem == "pacifism":  # this totem stacks
                        PACIFISM.append(victim)
                    elif totem == "influence":
                        INFLUENCE.add(victim)
                    elif totem == "exchange":
                        EXCHANGE.add(victim)
                    elif totem == "lycanthropy":
                        LYCANTHROPY.add(victim)
                    elif totem == "luck":
                        LUCK.add(victim)
                    elif totem == "pestilence":
                        PESTILENCE.add(victim)
                    elif totem == "retribution":
                        RETRIBUTION.add(victim)
                    elif totem == "misdirection":
                        MISDIRECTION.add(victim)
                    elif totem == "deceit":
                        DECEIT.add(victim)
                    else:
                        event = Event("apply_totem", {})
                        event.dispatch(var, rolename, totem, shaman, victim)

                    if target is not victim:
                        shaman.send(messages["totem_retarget"].format(
                            victim, target))
                    LASTGIVEN[shaman][totem].append(victim)
                    havetotem.append(victim)

    @event_listener("del_player",
                    listener_id="shamans.<{}>.del_player".format(rolename))
    def on_del_player(evt, var, player, all_roles, death_triggers):
        for a, b in list(SHAMANS.items()):
            if player is a:
                del SHAMANS[a]
            else:
                for totem, c in b.items():
                    if player in c:
                        SHAMANS[a][totem].remove(player)
        del RETARGET[:player:]
        for a, b in list(RETARGET.items()):
            for c, d in list(b.items()):
                if player in (c, d):
                    del RETARGET[a][c]

    @event_listener("chk_nightdone",
                    listener_id="shamans.<{}>.chk_nightdone".format(rolename))
    def on_chk_nightdone(evt, var):
        # only count shaman as acted if they've given out all of their totems
        for shaman in SHAMANS:
            totemcount = sum(TOTEMS[shaman].values())
            given = len(
                list(itertools.chain.from_iterable(SHAMANS[shaman].values())))
            if given == totemcount:
                evt.data["acted"].append(shaman)
        evt.data["nightroles"].extend(get_all_players((rolename, )))

    @event_listener(
        "get_role_metadata",
        listener_id="shamans.<{}>.get_role_metadata".format(rolename))
    def on_get_role_metadata(evt, var, kind):
        if kind == "night_kills":
            # only add shamans here if they were given a death totem
            # even though retribution kills, it is given a special kill message
            evt.data[rolename] = list(
                itertools.chain.from_iterable(TOTEMS.values())).count("death")

    @event_listener("new_role",
                    listener_id="shamans.<{}>.new_role".format(rolename))
    def on_new_role(evt, var, player, old_role):
        if evt.params.inherit_from in TOTEMS and old_role != rolename and evt.data[
                "role"] == rolename:
            totems = TOTEMS.pop(evt.params.inherit_from)
            del SHAMANS[:evt.params.inherit_from:]
            del LASTGIVEN[:evt.params.inherit_from:]

            if knows_totem:
                evt.data["messages"].append(totem_message(totems))
            TOTEMS[player] = totems

    @event_listener("swap_role_state",
                    listener_id="shamans.<{}>.swap_role_state".format(rolename)
                    )
    def on_swap_role_state(evt, var, actor, target, role):
        if role == rolename and actor in TOTEMS and target in TOTEMS:
            TOTEMS[actor], TOTEMS[target] = TOTEMS[target], TOTEMS[actor]
            del SHAMANS[:actor:]
            del SHAMANS[:target:]
            del LASTGIVEN[:actor:]
            del LASTGIVEN[:target:]

            if knows_totem:
                evt.data["actor_messages"].append(totem_message(TOTEMS[actor]))
                evt.data["target_messages"].append(
                    totem_message(TOTEMS[target]))

    @event_listener("default_totems",
                    priority=3,
                    listener_id="shamans.<{}>.default_totems".format(rolename))
    def add_shaman(evt, chances):
        evt.data["shaman_roles"].add(rolename)

    @event_listener(
        "transition_night_end",
        listener_id="shamans.<{}>.on_transition_night_end".format(rolename))
    def on_transition_night_end(evt, var):
        if var.NIGHT_COUNT == 0 or not get_all_players((rolename, )):
            return
        if var.CURRENT_GAMEMODE.TOTEM_CHANCES["lycanthropy"][rolename] > 0:
            status.add_lycanthropy_scope(var, All)
        if var.CURRENT_GAMEMODE.TOTEM_CHANCES["luck"][rolename] > 0:
            status.add_misdirection_scope(var, All, as_target=True)
        if var.CURRENT_GAMEMODE.TOTEM_CHANCES["misdirection"][rolename] > 0:
            status.add_misdirection_scope(var, All, as_actor=True)

    if knows_totem:

        @event_listener("myrole",
                        listener_id="shamans.<{}>.on_myrole".format(rolename))
        def on_myrole(evt, var, user):
            if evt.data[
                    "role"] == rolename and var.PHASE == "night" and user not in SHAMANS:
                evt.data["messages"].append(totem_message(TOTEMS[user]))

    return (TOTEMS, LASTGIVEN, SHAMANS, RETARGET)