Exemplo n.º 1
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    if not death_triggers or "mad scientist" not in all_roles:
        return

    target1, target2 = _get_targets(var, get_players(), player)

    prots1 = try_protection(var, target1, player, "mad scientist",
                            "mad_scientist_fail")
    prots2 = try_protection(var, target2, player, "mad scientist",
                            "mad_scientist_fail")
    if prots1:
        channels.Main.send(*prots1)
    if prots2:
        channels.Main.send(*prots2)

    kill1 = prots1 is None and add_dying(
        var, target1, killer_role="mad scientist", reason="mad_scientist")
    kill2 = prots2 is None and target1 is not target2 and add_dying(
        var, target2, killer_role="mad scientist", reason="mad_scientist")

    role1 = kill1 and get_reveal_role(target1)
    role2 = kill2 and get_reveal_role(target2)
    if kill1 and kill2:
        to_send = "mad_scientist_kill"
        debuglog(
            player.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(
                target1, get_main_role(target1), target2,
                get_main_role(target2)))
    elif kill1:
        to_send = "mad_scientist_kill_single"
        debuglog(
            player.nick,
            "(mad scientist) KILL: {0} ({1})".format(target1,
                                                     get_main_role(target1)))
    elif kill2:
        to_send = "mad_scientist_kill_single"
        debuglog(
            player.nick,
            "(mad scientist) KILL: {0} ({1})".format(target2,
                                                     get_main_role(target2)))
        # swap the targets around to show the proper target
        target1, target2 = target2, target1
        role1, role2 = role2, role1
    else:
        to_send = "mad_scientist_fail"
        debuglog(player.nick, "(mad scientist) KILL FAIL")

    if to_send != "mad_scientist_fail" and var.ROLE_REVEAL not in ("on",
                                                                   "team"):
        to_send += "_no_reveal"

    channels.Main.send(messages[to_send].format(player, target1, role1,
                                                target2, role2))
Exemplo n.º 2
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    if not death_triggers or "mad scientist" not in all_roles:
        return

    target1, target2 = _get_targets(var, get_players(), player)

    prots1 = try_protection(var, target1, player, "mad scientist", "mad_scientist_fail")
    prots2 = try_protection(var, target2, player, "mad scientist", "mad_scientist_fail")
    if prots1:
        channels.Main.send(*prots1)
    if prots2:
        channels.Main.send(*prots2)

    kill1 = prots1 is None and add_dying(var, target1, killer_role="mad scientist", reason="mad_scientist")
    kill2 = prots2 is None and target1 is not target2 and add_dying(var, target2, killer_role="mad scientist", reason="mad_scientist")

    if kill1:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill"].format(player, target1, an1, r1, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_no_reveal"].format(player, target1, target2)
            channels.Main.send(tmsg)
            debuglog(player.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(target1, get_main_role(target1), target2, get_main_role(target2)))
        else:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(player, target1, an1, r1)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(player, target1)
            channels.Main.send(tmsg)
            debuglog(player.nick, "(mad scientist) KILL: {0} ({1})".format(target1, get_main_role(target1)))
    else:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(player, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(player, target2)
            channels.Main.send(tmsg)
            debuglog(player.nick, "(mad scientist) KILL: {0} ({1})".format(target2, get_main_role(target2)))
        else:
            tmsg = messages["mad_scientist_fail"].format(player)
            channels.Main.send(tmsg)
            debuglog(player.nick, "(mad scientist) KILL FAIL")
Exemplo n.º 3
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    if player in TARGETED.values():
        for x, y in list(TARGETED.items()):
            if y is player:
                del TARGETED[x]
                PREV_ACTED.discard(x)

    if death_triggers and "assassin" in all_roles and player in TARGETED:
        target = TARGETED[player]
        del TARGETED[player]
        PREV_ACTED.discard(player)
        if target in get_players():
            protected = try_protection(var, target, player, "assassin", "assassin_fail")
            if protected is not None:
                channels.Main.send(*protected)
                return
            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(target)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                message = messages["assassin_success"].format(player, target, an, role)
            else:
                message = messages["assassin_success_no_reveal"].format(player, target)
            channels.Main.send(message)
            debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target)))
            add_dying(var, target, killer_role=evt.params.main_role, reason="assassin")
Exemplo n.º 4
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    for h, v in list(KILLS.items()):
        if v is player:
            h.send(messages["hunter_discard"])
            del KILLS[h]
        elif h is player:
            del KILLS[h]
    if death_triggers and "dullahan" in all_roles:
        pl = get_players()
        with TARGETS[player].intersection(pl) as targets:
            if targets:
                target = random.choice(list(targets))
                protected = try_protection(var, target, player, "dullahan", "dullahan_die")
                if protected is not None:
                    channels.Main.send(*protected)
                    return

                if var.ROLE_REVEAL in ("on", "team"):
                    role = get_reveal_role(target)
                    an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                    channels.Main.send(messages["dullahan_die_success"].format(player, target, an, role))
                else:
                    channels.Main.send(messages["dullahan_die_success_noreveal"].format(player, target))
                debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target)))
                add_dying(var, target, "dullahan", "dullahan_die")
Exemplo n.º 5
0
def on_chk_decision_lynch5(evt, 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 is not votee:
            protected = try_protection(var,
                                       target,
                                       attacker=votee,
                                       attacker_role="shaman",
                                       reason="totem_desperation")
            if protected is not None:
                channels.Main.send(*protected)
                return

            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)
            channels.Main.send(tmsg)
            add_dying(var,
                      target,
                      killer_role="shaman",
                      reason="totem_desperation")
Exemplo n.º 6
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(users._get(target))  # FIXME
                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)
Exemplo n.º 7
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)
Exemplo n.º 8
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    for h, v in list(KILLS.items()):
        if v is player:
            h.send(messages["hunter_discard"])
            del KILLS[h]
        elif h is player:
            del KILLS[h]
    if death_triggers and "dullahan" in all_roles:
        pl = get_players()
        with TARGETS[player].intersection(pl) as targets:
            if targets:
                target = random.choice(list(targets))
                protected = try_protection(var, target, player, "dullahan",
                                           "dullahan_die")
                if protected is not None:
                    channels.Main.send(*protected)
                    return

                if var.ROLE_REVEAL in ("on", "team"):
                    role = get_reveal_role(target)
                    channels.Main.send(messages["dullahan_die_success"].format(
                        player, target, role))
                else:
                    channels.Main.send(
                        messages["dullahan_die_success_noreveal"].format(
                            player, target))
                debuglog(
                    "{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(
                        player, target, get_main_role(target)))
                add_dying(var, target, "dullahan", "dullahan_die")
Exemplo n.º 9
0
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
    for h, v in list(KILLS.items()):
        if v is user:
            h.send(messages["hunter_discard"])
            del KILLS[h]
        elif h is user:
            del KILLS[h]
    if death_triggers and "dullahan" in allroles:
        pl = evt.data["pl"]
        targets = TARGETS[user].intersection(pl)
        if targets:
            target = random.choice(list(targets))
            prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
            aevt = Event("assassinate", {
                "pl": evt.data["pl"],
                "target": target
            },
                         del_player=evt.params.del_player,
                         deadlist=evt.params.deadlist,
                         original=evt.params.original,
                         refresh_pl=evt.params.refresh_pl,
                         message_prefix="dullahan_die_",
                         source="dullahan",
                         killer=user,
                         killer_mainrole=mainrole,
                         killer_allroles=allroles,
                         prots=prots)
            while len(prots) > 0:
                # an event can read the current active protection and cancel or redirect the assassination
                # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
                # so that it cannot be used again (if the protection is meant to be usable once-only)
                if not aevt.dispatch(var, user, target, prots[0]):
                    evt.data["pl"] = aevt.data["pl"]
                    if target is not aevt.data["target"]:
                        target = aevt.data["target"]
                        prots = deque(var.ACTIVE_PROTECTIONS[target.nick])
                        aevt.params.prots = prots
                        continue
                    return
                prots.popleft()

            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(target)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                channels.Main.send(messages["dullahan_die_success"].format(
                    user, target, an, role))
            else:
                channels.Main.send(
                    messages["dullahan_die_success_noreveal"].format(
                        user, target))
            debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(
                user, target, get_main_role(target)))
            evt.params.del_player(target,
                                  end_game=False,
                                  killer_role="dullahan",
                                  deadlist=evt.params.deadlist,
                                  original=evt.params.original,
                                  ismain=False)
            evt.data["pl"] = evt.params.refresh_pl(pl)
Exemplo n.º 10
0
    def on_transition_day_resolve_end(evt, var, victims):
        for victim in list(evt.data["dead"]):
            if GUNNERS.get(
                    victim) and "@wolves" in evt.data["killers"][victim]:
                if random.random() < var.GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE:
                    # pick a random wolf to be shot
                    wolves = [
                        wolf for wolf in get_players(Wolf & Killer)
                        if wolf not in evt.data["dead"]
                    ]
                    if wolves:
                        shot = random.choice(wolves)
                        event = Event("gun_shoot", {"hit": True, "kill": True})
                        event.dispatch(var, victim, shot, rolename)
                        GUNNERS[victim] -= 1  # deduct the used bullet
                        if event.data["hit"] and event.data["kill"]:
                            to_send = "gunner_killed_wolf_overnight_no_reveal"
                            if var.ROLE_REVEAL in ("on", "team"):
                                to_send = "gunner_killed_wolf_overnight"
                            evt.data["message"][victim].append(
                                messages[to_send].format(
                                    victim, shot, get_reveal_role(shot)))
                            evt.data["dead"].append(shot)
                            evt.data["killers"][shot].append(victim)
                        elif event.data["hit"]:
                            # shot hit, but didn't kill
                            evt.data["message"][victim].append(
                                messages["gunner_shoot_overnight_hit"].format(
                                    victim))
                            add_absent(var, shot, "wounded")
                        else:
                            # shot was fired and missed
                            evt.data["message"][victim].append(
                                messages["gunner_shoot_overnight_missed"].
                                format(victim))

                # let wolf steal gun if the gunner has any bullets remaining
                # this gives the looter the "wolf gunner" secondary role
                # if the wolf gunner role isn't loaded, guns cannot be stolen regardless of var.WOLF_STEALS_GUN
                if var.WOLF_STEALS_GUN and GUNNERS[
                        victim] and "wolf gunner" in _rolestate:
                    possible = get_players(Wolf & Killer)
                    random.shuffle(possible)
                    for looter in possible:
                        if looter not in evt.data["dead"]:
                            break
                    else:
                        return  # no live wolf, nothing to do here

                    _rolestate["wolf gunner"]["GUNNERS"][
                        looter] = _rolestate["wolf gunner"]["GUNNERS"].get(
                            looter, 0) + 1
                    del GUNNERS[victim]
                    var.ROLES["wolf gunner"].add(looter)
                    looter.send(messages["wolf_gunner"].format(victim))
Exemplo n.º 11
0
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
    global ALL_SUCC_IDLE
    if "succubus" not in allroles:
        return
    if user in VISITED:
        # if it's night, also unentrance the person they visited
        if var.PHASE == "night" and var.GAMEPHASE == "night":
            if VISITED[user] in ENTRANCED:
                ENTRANCED.discard(VISITED[user])
                ENTRANCED_DYING.discard(VISITED[user])
                VISITED[user].send(messages["entranced_revert_win"])
        del VISITED[user]

    # if all succubi are dead, one of two things happen:
    # 1. if all succubi idled out (every last one of them), un-entrance people
    # 2. otherwise, kill all entranced people immediately, they still remain entranced (and therefore lose)
    # death_triggers is False for an idle-out, so we use that to determine which it is
    if death_triggers:
        ALL_SUCC_IDLE = False
    if not get_all_players(("succubus",)):
        entranced_alive = ENTRANCED.difference(evt.params.deadlist).intersection(evt.data["pl"])
        if ALL_SUCC_IDLE:
            while ENTRANCED:
                e = ENTRANCED.pop()
                e.send(messages["entranced_revert_win"])
        elif entranced_alive:
            msg = []
            # Run in two loops so we can play the message for everyone dying at once before we actually
            # kill any of them off (if we killed off first, the message order would be wrong wrt death chains)
            comma = ""
            if var.ROLE_REVEAL in ("on", "team"):
                comma = ","
            for e in entranced_alive:
                if var.ROLE_REVEAL in ("on", "team"):
                    role = get_reveal_role(e)
                    an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                    msg.append("\u0002{0}\u0002, a{1} \u0002{2}\u0002".format(e, an, role))
                else:
                    msg.append("\u0002{0}\u0002".format(e))
            if len(msg) == 1:
                channels.Main.send(messages["succubus_die_kill"].format(msg[0] + comma))
            elif len(msg) == 2:
                channels.Main.send(messages["succubus_die_kill"].format(msg[0] + comma + " and " + msg[1] + comma))
            else:
                channels.Main.send(messages["succubus_die_kill"].format(", ".join(msg[:-1]) + ", and " + msg[-1] + comma))
            for e in entranced_alive:
                # to ensure we do not double-kill someone, notify all child deaths that we'll be
                # killing off everyone else that is entranced so they don't need to bother
                dlc = list(evt.params.deadlist)
                dlc.extend(entranced_alive - {e})
                debuglog("{0} (succubus) SUCCUBUS DEATH KILL: {1} ({2})".format(user, e, get_main_role(e)))
                evt.params.del_player(e, end_game=False, killer_role="succubus",
                    deadlist=dlc, original=evt.params.original, ismain=False)
                evt.data["pl"] = evt.params.refresh_pl(evt.data["pl"])
        ENTRANCED_DYING.clear()
Exemplo n.º 12
0
def kill_off_dying_players(evt, var, victims):
    for victim in DYING:
        if victim not in evt.data["dead"]:
            evt.data["novictmsg"] = False
            evt.data["dead"].append(victim)

            to_send = "death_no_reveal"
            if var.ROLE_REVEAL in ("on", "team"):
                to_send = "death"
            evt.data["message"][victim].append(messages[to_send].format(
                victim, get_reveal_role(victim)))
Exemplo n.º 13
0
def on_transition_day_resolve_end(evt, var, victims):
    for victim in victims:
        if victim in evt.data["dead"] and victim in VISITED.values() and "@wolves" in evt.data["killers"][victim]:
            for hlt in VISITED:
                if VISITED[hlt] is victim and hlt not in evt.data["dead"]:
                    role = get_reveal_role(hlt)
                    to_send = "visited_victim_noreveal"
                    if var.ROLE_REVEAL in ("on", "team"):
                        to_send = "visited_victim"
                    evt.data["message"][hlt].append(messages[to_send].format(hlt, role))
                    evt.data["dead"].append(hlt)
                    evt.data["killers"][hlt].append("@wolves")
Exemplo n.º 14
0
def kill_off_dying_players(evt, var, victims):
    for victim in DYING:
        if victim not in evt.data["dead"]:
            evt.data["novictmsg"] = False
            evt.data["dead"].append(victim)

            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(victim)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                evt.data["message"][victim].append(messages["death"].format(victim, an, role))
            else:
                evt.data["message"][victim].append(messages["death_no_reveal"].format(victim))
Exemplo n.º 15
0
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
    if player in TARGETED.values():
        for x, y in list(TARGETED.items()):
            if y is player:
                del TARGETED[x]
                PREV_ACTED.discard(x)

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

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

            if not prots:
                if var.ROLE_REVEAL in ("on", "team"):
                    role = get_reveal_role(target)
                    an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                    message = messages["assassin_success"].format(player, target, an, role)
                else:
                    message = messages["assassin_success_no_reveal"].format(player, target)
                channels.Main.send(message)
                debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target)))
                evt.params.del_player(target, end_game=False, killer_role=mainrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
                evt.data["pl"] = evt.params.refresh_pl(aevt.data["pl"])
Exemplo n.º 16
0
def on_lynch(evt, var, votee, voters):
    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 is not votee:
            protected = try_protection(var, target, attacker=votee, attacker_role="shaman", reason="totem_desperation")
            if protected is not None:
                channels.Main.send(*protected)
                return

            to_send = "totem_desperation_no_reveal"
            if var.ROLE_REVEAL in ("on", "team"):
                to_send = "totem_desperation"
            channels.Main.send(messages[to_send].format(votee, target, get_reveal_role(target)))
            status.add_dying(var, target, killer_role="shaman", reason="totem_desperation")
Exemplo n.º 17
0
def on_transition_day_resolve6(evt, 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 evt.data["protected"].get(victim):
        return
    if victim in var.ROLES["lycan"] and victim in evt.data[
            "onlybywolves"] and victim.nick not in var.IMMUNIZED:
        return
    # END checks to remove

    if victim.nick in RETRIBUTION:
        killers = list(evt.data["killers"].get(victim, []))
        loser = None
        while killers:
            loser = random.choice(killers)
            if loser in evt.data["dead"] or victim is loser:
                killers.remove(loser)
                continue
            break
        if loser in evt.data["dead"] or victim is loser:
            loser = None
        ret_evt = Event("retribution_kill", {"target": loser, "message": []})
        ret_evt.dispatch(var, victim, loser)
        loser = ret_evt.data["target"]
        evt.data["message"].extend(ret_evt.data["message"])
        if loser in evt.data["dead"] or victim is loser:
            loser = None
        if loser is not None:
            prots = deque(var.ACTIVE_PROTECTIONS[loser.nick])
            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(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))
Exemplo n.º 18
0
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
    if death_triggers and player in LOVERS:
        lovers = set(LOVERS[player])
        for lover in lovers:
            if lover not in evt.data["pl"]:
                continue # already died somehow
            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(lover)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                message = messages["lover_suicide"].format(lover, an, role)
            else:
                message = messages["lover_suicide_no_reveal"].format(lover)
            channels.Main.send(message)
            debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(lover, get_main_role(lover), player, mainrole))
            evt.params.del_player(lover, end_game=False, killer_role=evt.params.killer_role, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
            evt.data["pl"] = evt.params.refresh_pl(evt.data["pl"])
Exemplo n.º 19
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    MATCHMAKERS.discard(player)
    if death_triggers and player in LOVERS:
        lovers = set(LOVERS[player])
        for lover in lovers:
            if lover not in get_players():
                continue # already died somehow
            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(lover)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                message = messages["lover_suicide"].format(lover, an, role)
            else:
                message = messages["lover_suicide_no_reveal"].format(lover)
            channels.Main.send(message)
            debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(lover, get_main_role(lover), player, evt.params.main_role))
            add_dying(var, lover, killer_role=evt.params.killer_role, reason="lover_suicide")
Exemplo n.º 20
0
def on_transition_day_resolve_end(evt, var, victims):
    for victim in victims:
        if victim in evt.data["dead"] and victim in VISITED.values(
        ) and "@wolves" in evt.data["killers"][victim]:
            for succubus in VISITED:
                if VISITED[succubus] is victim and succubus not in evt.data[
                        "dead"]:
                    if var.ROLE_REVEAL in ("on", "team"):
                        evt.data["message"][succubus].append(
                            messages["visited_victim"].format(
                                succubus, get_reveal_role(succubus)))
                    else:
                        evt.data["message"][succubus].append(
                            messages["visited_victim_noreveal"].format(
                                succubus))
                    evt.data["dead"].append(succubus)
Exemplo n.º 21
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)
            var.DEAD.add(player)
            # notify listeners that the player died for possibility of chained deaths
            evt = Event("del_player", {},
                        killer_role=killer_role,
                        main_role=main_role,
                        reveal_role=reveal_role,
                        reason=reason)
            evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
            evt.dispatch(var, player, all_roles, evt_death_triggers)

        # notify listeners that all deaths have resolved
        # FIXME: end_game is a temporary hack until we move state transitions into the event loop
        # (priority 10 listener sets prevent_default if end_game=True and game is ending; that's another temporary hack)
        # Once hacks are removed, this function will not have any return value and the end_game kwarg will go away
        evt = Event("kill_players", {}, end_game=end_game)
        return not evt.dispatch(var, dead)
Exemplo n.º 22
0
def on_transition_day_resolve_end(evt, var, victims):
    for victim in victims + evt.data["bitten"]:
        if victim in evt.data["dead"] and victim in VISITED.values() and (
                victim in evt.data["bywolves"]
                or victim in evt.data["bitten"]):
            for hlt in VISITED:
                if VISITED[hlt] is victim and hlt not in evt.data[
                        "bitten"] and hlt not in evt.data["dead"]:
                    if var.ROLE_REVEAL in ("on", "team"):
                        evt.data["message"].append(
                            messages["visited_victim"].format(
                                hlt, get_reveal_role(hlt)))
                    else:
                        evt.data["message"].append(
                            messages["visited_victim_noreveal"].format(hlt))
                    evt.data["bywolves"].add(hlt)
                    evt.data["onlybywolves"].add(hlt)
                    evt.data["dead"].append(hlt)
Exemplo n.º 23
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    MATCHMAKERS.discard(player)
    ACTED.discard(player)
    if death_triggers and player in LOVERS:
        lovers = set(LOVERS[player])
        for lover in lovers:
            if lover not in get_players():
                continue  # already died somehow
            to_send = "lover_suicide_no_reveal"
            if var.ROLE_REVEAL in ("on", "team"):
                to_send = "lover_suicide"
            channels.Main.send(messages[to_send].format(
                lover, get_reveal_role(lover)))
            debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(
                lover, get_main_role(lover), player, evt.params.main_role))
            add_dying(var,
                      lover,
                      killer_role=evt.params.killer_role,
                      reason="lover_suicide")
Exemplo n.º 24
0
def on_transition_day_resolve6(evt, var, victims):
    for victim in victims:
        if victim in RETRIBUTION:
            killers = list(evt.data["killers"].get(victim, []))
            loser = None
            while killers:
                loser = random.choice(killers)
                if loser in evt.data["dead"] or victim is loser:
                    killers.remove(loser)
                    continue
                break
            if loser in evt.data["dead"] or victim is loser:
                loser = None
            ret_evt = Event("retribution_kill", {
                "target": loser,
                "message": []
            })
            ret_evt.dispatch(var, victim, loser)
            loser = ret_evt.data["target"]
            evt.data["message"][loser].extend(ret_evt.data["message"])
            if loser in evt.data["dead"] or victim is loser:
                loser = None
            if loser is not None:
                protected = try_protection(var, loser, victim,
                                           get_main_role(victim),
                                           "retribution_totem")
                if protected is not None:
                    channels.Main.send(*protected)
                    return

                evt.data["dead"].append(loser)
                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"][loser].append(
                        messages["totem_death"].format(victim, loser, an,
                                                       role))
                else:
                    evt.data["message"][loser].append(
                        messages["totem_death_no_reveal"].format(
                            victim, loser))
Exemplo n.º 25
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    MATCHMAKERS.discard(player)
    if death_triggers and player in LOVERS:
        lovers = set(LOVERS[player])
        for lover in lovers:
            if lover not in get_players():
                continue  # already died somehow
            if var.ROLE_REVEAL in ("on", "team"):
                role = get_reveal_role(lover)
                an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
                message = messages["lover_suicide"].format(lover, an, role)
            else:
                message = messages["lover_suicide_no_reveal"].format(lover)
            channels.Main.send(message)
            debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(
                lover, get_main_role(lover), player, evt.params.main_role))
            add_dying(var,
                      lover,
                      killer_role=evt.params.killer_role,
                      reason="lover_suicide")
Exemplo n.º 26
0
    def on_transition_day_resolve_end(evt, var, victims):
        for victim in list(evt.data["dead"]):
            if GUNNERS.get(
                    victim) and "@wolves" in evt.data["killers"][victim]:
                if random.random() < var.GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE:
                    # pick a random wolf to be shot
                    wolfset = [
                        wolf for wolf in get_players(Wolf)
                        if wolf not in evt.data["dead"]
                    ]
                    if wolfset:
                        deadwolf = random.choice(wolfset)
                        if var.ROLE_REVEAL in ("on", "team"):
                            evt.data["message"][victim].append(
                                messages["gunner_killed_wolf_overnight"].
                                format(victim, deadwolf,
                                       get_reveal_role(deadwolf)))
                        else:
                            evt.data["message"][victim].append(messages[
                                "gunner_killed_wolf_overnight_no_reveal"].
                                                               format(
                                                                   victim,
                                                                   deadwolf))
                        evt.data["dead"].append(deadwolf)
                        evt.data["killers"][deadwolf].append(victim)
                        GUNNERS[victim] -= 1  # deduct the used bullet

                if var.WOLF_STEALS_GUN and GUNNERS[
                        victim]:  # might have used up the last bullet or something
                    possible = get_players(Wolfchat)
                    random.shuffle(possible)
                    for looter in possible:
                        if looter not in evt.data["dead"]:
                            break
                    else:
                        return  # no live wolf, nothing to do here

                    GUNNERS[looter] = GUNNERS.get(looter, 0) + 1
                    del GUNNERS[victim]
                    var.ROLES[rolename].add(looter)
                    looter.send(messages["wolf_gunner"].format(victim))
Exemplo n.º 27
0
    def shoot(var, wrapper, message):
        """Use this to fire off a bullet at someone in the day if you have bullets."""
        if not GUNNERS[wrapper.source]:
            wrapper.pm(messages["no_bullets"])
            return

        target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="gunner_target_self")
        if not target:
            return

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

        GUNNERS[wrapper.source] -= 1

        gun_evt = Event("gun_chances", {"hit": 0, "miss": 0, "headshot": 0})
        gun_evt.dispatch(var, wrapper.source, rolename)

        rand = random.random() # need to save it

        shoot_evt = Event("gun_shoot", {"hit": rand <= gun_evt.data["hit"], "kill": random.random() <= gun_evt.data["headshot"]})
        shoot_evt.dispatch(var, wrapper.source, target)

        realrole = get_main_role(target)
        targrole = get_reveal_role(target)

        if shoot_evt.data["hit"]:
            wrapper.send(messages["shoot_success"].format(wrapper.source, target))
            an = "n" if targrole.startswith(("a", "e", "i", "o", "u")) else ""
            if realrole in Wolf:
                if var.ROLE_REVEAL == "on":
                    wrapper.send(messages["gunner_victim_wolf_death"].format(target, an, targrole))
                else: # off and team
                    wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(target))
                add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim")
                if kill_players(var):
                    return
            elif shoot_evt.data["kill"]:
                accident = "accidentally "
                if gun_evt.data["headshot"] == 1: # would always headshot
                    accident = ""
                wrapper.send(messages["gunner_victim_villager_death"].format(target, accident))
                if var.ROLE_REVEAL in ("on", "team"):
                    wrapper.send(messages["gunner_victim_role"].format(an, targrole))
                add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim")
                if kill_players(var):
                    return
            else:
                wrapper.send(messages["gunner_victim_injured"].format(target))
                add_absent(var, target, "wounded")
                from src.wolfgame import chk_decision, chk_win
                chk_decision()
                chk_win()

        elif rand <= gun_evt.data["hit"] + gun_evt.data["miss"]:
            wrapper.send(messages["gunner_miss"].format(wrapper.source))
        else: # BOOM! your gun explodes, you're dead
            if var.ROLE_REVEAL in ("on", "team"):
                wrapper.send(messages["gunner_suicide"].format(wrapper.source, get_reveal_role(wrapper.source)))
            else:
                wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source))
            add_dying(var, wrapper.source, killer_role="villager", reason="gunner_suicide") # blame explosion on villager's shoddy gun construction or something
            kill_players(var)
Exemplo n.º 28
0
    def on_transition_day_resolve_end(evt, var, victims):
        for victim in list(evt.data["dead"]):
            if GUNNERS.get(victim) and "@wolves" in evt.data["killers"][victim]:
                if random.random() < var.GUNNER_KILLS_WOLF_AT_NIGHT_CHANCE:
                    # pick a random wolf to be shot
                    wolfset = [wolf for wolf in get_players(Wolf) if wolf not in evt.data["dead"]]
                    if wolfset:
                        deadwolf = random.choice(wolfset)
                        if var.ROLE_REVEAL in ("on", "team"):
                            evt.data["message"][victim].append(messages["gunner_killed_wolf_overnight"].format(victim, deadwolf, get_reveal_role(deadwolf)))
                        else:
                            evt.data["message"][victim].append(messages["gunner_killed_wolf_overnight_no_reveal"].format(victim, deadwolf))
                        evt.data["dead"].append(deadwolf)
                        evt.data["killers"][deadwolf].append(victim)
                        GUNNERS[victim] -= 1 # deduct the used bullet

                if var.WOLF_STEALS_GUN and GUNNERS[victim]: # might have used up the last bullet or something
                    possible = get_players(Wolfchat)
                    random.shuffle(possible)
                    for looter in possible:
                        if looter not in evt.data["dead"]:
                            break
                    else:
                        return # no live wolf, nothing to do here

                    GUNNERS[looter] = GUNNERS.get(looter, 0) + 1
                    del GUNNERS[victim]
                    var.ROLES[rolename].add(looter)
                    looter.send(messages["wolf_gunner"].format(victim))
Exemplo n.º 29
0
def chk_decision(var, *, timeout=False):
    with var.GRAVEYARD_LOCK:
        players = set(get_players()) - get_absent(var)
        avail = len(players)
        needed = avail // 2 + 1

        to_vote = []

        for votee, voters in VOTES.items():
            votes = (set(voters)
                     | get_forced_votes(var, votee)) - get_forced_abstains(var)
            if sum(get_vote_weight(var, x) for x in votes) >= needed:
                to_vote.append(votee)
                break

        behaviour_evt = Event("lynch_behaviour", {
            "num_lynches": 1,
            "kill_ties": False,
            "force": timeout
        },
                              votes=VOTES,
                              players=avail)
        behaviour_evt.dispatch(var)

        num_lynches = behaviour_evt.data["num_lynches"]
        kill_ties = behaviour_evt.data["kill_ties"]
        force = behaviour_evt.data["force"]

        abstaining = False
        if not to_vote:
            if len(ABSTAINS | get_forced_abstains(var)) >= avail / 2:
                abstaining = True
            elif force:
                voting = []
                if VOTES:
                    plurality = [(x, len(y)) for x, y in VOTES.items()]
                    plurality.sort(key=lambda x: x[1])
                    votee, value = plurality.pop()
                    max_value = value
                    # Fetch all of the highest ties, exit out if we find someone lower
                    # If everyone is tied, then at some point plurality will be empty,
                    # but the values will still be at the max. Everything's fine, just break
                    while value == max_value:
                        voting.append(votee)
                        if not plurality:
                            break
                        votee, value = plurality.pop()

                if len(voting) == 1:
                    to_vote.append(voting[0])
                elif voting and kill_ties:
                    if set(voting) == set(
                            get_players()
                    ):  # killing everyone off? have you considered not doing that
                        abstaining = True
                    else:
                        to_vote.extend(voting)
                else:
                    abstaining = True

        if abstaining:
            for forced_abstainer in get_forced_abstains(var):
                if forced_abstainer not in ABSTAINS:  # did not explicitly abstain
                    channels.Main.send(messages["player_meek_abstain"].format(
                        forced_abstainer))

            abstain_evt = Event("abstain", {})
            abstain_evt.dispatch(var, ABSTAINS | get_forced_abstains(var))

            global ABSTAINED
            ABSTAINED = True
            channels.Main.send(messages["village_abstain"])

            from src.wolfgame import transition_night
            transition_night()

        if to_vote:
            global LYNCHED
            LYNCHED += len(
                to_vote)  # track how many people we've lynched today

            if timeout:
                channels.Main.send(messages["sunset_lynch"])

            for votee in to_vote:
                voters = list(VOTES[votee])
                for forced_voter in get_forced_votes(var, votee):
                    if forced_voter not in voters:  # did not explicitly vote
                        channels.Main.send(messages["impatient_vote"].format(
                            forced_voter, votee))
                        voters.append(
                            forced_voter
                        )  # they need to be counted as voting for them still

                if not try_lynch_immunity(var, votee):
                    lynch_evt = Event("lynch", {}, players=avail)
                    if lynch_evt.dispatch(var, votee, voters):
                        if var.ROLE_REVEAL in ("on", "team"):
                            rrole = get_reveal_role(votee)
                            an = "n" if rrole.startswith(
                                ("a", "e", "i", "o", "u")) else ""
                            lmsg = random.choice(
                                messages["lynch_reveal"]).format(
                                    votee, an, rrole)
                        else:
                            lmsg = random.choice(
                                messages["lynch_no_reveal"]).format(votee)
                        channels.Main.send(lmsg)
                        add_dying(var, votee, "villager", "lynch")

            kill_players(var, end_game=False)  # FIXME

        elif timeout:
            channels.Main.send(messages["sunset"])

        from src.wolfgame import chk_win
        if chk_win():
            return  # game ended, just exit out

        if timeout or LYNCHED >= num_lynches:
            from src.wolfgame import transition_night
            transition_night()
Exemplo n.º 30
0
def on_transition_day_resolve_end(evt, var, victims):
    for victim in victims:
        if victim in evt.data["dead"] and victim in VISITED.values() and "@wolves" in evt.data["killers"][victim]:
            for hlt in VISITED:
                if VISITED[hlt] is victim and hlt not in evt.data["dead"]:
                    if var.ROLE_REVEAL in ("on", "team"):
                        evt.data["message"][hlt].append(messages["visited_victim"].format(hlt, get_reveal_role(hlt)))
                    else:
                        evt.data["message"][hlt].append(messages["visited_victim_noreveal"].format(hlt))
                    evt.data["dead"].append(hlt)
Exemplo n.º 31
0
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
    if not death_triggers or "mad scientist" not in allroles:
        return

    pl = evt.data["pl"]
    target1, target2 = _get_targets(var, pl, user)

    # apply protections (if applicable)
    prots1 = deque(var.ACTIVE_PROTECTIONS[target1.nick])
    prots2 = deque(var.ACTIVE_PROTECTIONS[target2.nick])
    # for this event, we don't tell the event that the other side is dying
    # this allows, e.g. a bodyguard and the person they are guarding to get splashed,
    # and the bodyguard to still sacrifice themselves to guard the other person
    aevt = Event("assassinate", {
        "pl": pl,
        "target": target1
    },
                 del_player=evt.params.del_player,
                 deadlist=evt.params.deadlist,
                 original=evt.params.original,
                 refresh_pl=evt.params.refresh_pl,
                 message_prefix="mad_scientist_fail_",
                 source="mad scientist",
                 killer=user,
                 killer_mainrole=mainrole,
                 killer_allroles=allroles,
                 prots=prots1)
    while len(prots1) > 0:
        # events may be able to cancel this kill
        if not aevt.dispatch(var, user, target1, prots1[0]):
            pl = aevt.data["pl"]
            if target1 is not aevt.data["target"]:
                target1 = aevt.data["target"]
                prots1 = deque(var.ACTIVE_PROTECTIONS[target1.nick])
                aevt.params.prots = prots1
                continue
            break
        prots1.popleft()
    aevt.data["target"] = target2
    aevt.params.prots = prots2
    while len(prots2) > 0:
        # events may be able to cancel this kill
        if not aevt.dispatch(var, user, target2, prots2[0]):
            pl = aevt.data["pl"]
            if target2 is not aevt.data["target"]:
                target2 = aevt.data["target"]
                prots2 = deque(var.ACTIVE_PROTECTIONS[target2.nick])
                aevt.params.prots = prots2
                continue
            break
        prots2.popleft()

    kill1 = target1 in pl and len(prots1) == 0
    kill2 = target2 in pl and len(prots2) == 0 and target1 is not target2

    if kill1:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill"].format(
                    user, target1, an1, r1, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_no_reveal"].format(
                    user, target1, target2)
            channels.Main.send(tmsg)
            debuglog(
                user.nick,
                "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(
                    target1, get_main_role(target1), target2,
                    get_main_role(target2)))
            # here we DO want to tell that the other one is dying already so chained deaths don't mess things up
            deadlist1 = evt.params.deadlist[:]
            deadlist1.append(target2)
            deadlist2 = evt.params.deadlist[:]
            deadlist2.append(target1)
            evt.params.del_player(target1,
                                  end_game=False,
                                  killer_role="mad scientist",
                                  deadlist=deadlist1,
                                  original=evt.params.original,
                                  ismain=False)
            evt.params.del_player(target2,
                                  end_game=False,
                                  killer_role="mad scientist",
                                  deadlist=deadlist2,
                                  original=evt.params.original,
                                  ismain=False)
            pl = evt.params.refresh_pl(pl)
        else:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(
                    user, target1, an1, r1)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(
                    user, target1)
            channels.Main.send(tmsg)
            debuglog(
                user.nick, "(mad scientist) KILL: {0} ({1})".format(
                    target1, get_main_role(target1)))
            evt.params.del_player(target1,
                                  end_game=False,
                                  killer_role="mad scientist",
                                  deadlist=evt.params.deadlist,
                                  original=evt.params.original,
                                  ismain=False)
            pl = evt.params.refresh_pl(pl)
    else:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(
                    user, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(
                    user, target2)
            channels.Main.send(tmsg)
            debuglog(
                user.nick, "(mad scientist) KILL: {0} ({1})".format(
                    target2, get_main_role(target2)))
            evt.params.del_player(target2,
                                  end_game=False,
                                  killer_role="mad scientist",
                                  deadlist=evt.params.deadlist,
                                  original=evt.params.original,
                                  ismain=False)
            pl = evt.params.refresh_pl(pl)
        else:
            tmsg = messages["mad_scientist_fail"].format(user)
            channels.Main.send(tmsg)
            debuglog(user.nick, "(mad scientist) KILL FAIL")

    evt.data["pl"] = pl
Exemplo n.º 32
0
def on_del_player(evt, var, player, all_roles, death_triggers):
    if not death_triggers or "mad scientist" not in all_roles:
        return

    target1, target2 = _get_targets(var, get_players(), player)

    prots1 = try_protection(var, target1, player, "mad scientist",
                            "mad_scientist_fail")
    prots2 = try_protection(var, target2, player, "mad scientist",
                            "mad_scientist_fail")
    if prots1:
        channels.Main.send(*prots1)
    if prots2:
        channels.Main.send(*prots2)

    kill1 = prots1 is None and add_dying(
        var, target1, killer_role="mad scientist", reason="mad_scientist")
    kill2 = prots2 is None and target1 is not target2 and add_dying(
        var, target2, killer_role="mad scientist", reason="mad_scientist")

    if kill1:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill"].format(
                    player, target1, an1, r1, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_no_reveal"].format(
                    player, target1, target2)
            channels.Main.send(tmsg)
            debuglog(
                player.nick,
                "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(
                    target1, get_main_role(target1), target2,
                    get_main_role(target2)))
        else:
            if var.ROLE_REVEAL in ("on", "team"):
                r1 = get_reveal_role(target1)
                an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(
                    player, target1, an1, r1)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(
                    player, target1)
            channels.Main.send(tmsg)
            debuglog(
                player.nick, "(mad scientist) KILL: {0} ({1})".format(
                    target1, get_main_role(target1)))
    else:
        if kill2:
            if var.ROLE_REVEAL in ("on", "team"):
                r2 = get_reveal_role(target2)
                an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else ""
                tmsg = messages["mad_scientist_kill_single"].format(
                    player, target2, an2, r2)
            else:
                tmsg = messages["mad_scientist_kill_single_no_reveal"].format(
                    player, target2)
            channels.Main.send(tmsg)
            debuglog(
                player.nick, "(mad scientist) KILL: {0} ({1})".format(
                    target2, get_main_role(target2)))
        else:
            tmsg = messages["mad_scientist_fail"].format(player)
            channels.Main.send(tmsg)
            debuglog(player.nick, "(mad scientist) KILL FAIL")
Exemplo n.º 33
0
def chk_decision(var, *, timeout=False):
    with var.GRAVEYARD_LOCK:
        players = set(get_players()) - get_absent(var)
        avail = len(players)
        needed = avail // 2 + 1

        to_vote = []

        for votee, voters in VOTES.items():
            votes = (set(voters) | get_forced_votes(var, votee)) - get_forced_abstains(var)
            if sum(get_vote_weight(var, x) for x in votes) >= needed:
                to_vote.append(votee)
                break

        behaviour_evt = Event("lynch_behaviour", {"num_lynches": 1, "kill_ties": False, "force": timeout}, votes=VOTES, players=avail)
        behaviour_evt.dispatch(var)

        num_lynches = behaviour_evt.data["num_lynches"]
        kill_ties = behaviour_evt.data["kill_ties"]
        force = behaviour_evt.data["force"]

        abstaining = False
        if not to_vote:
            if len(ABSTAINS | get_forced_abstains(var)) >= avail / 2:
                abstaining = True
            elif force:
                voting = []
                if VOTES:
                    plurality = [(x, len(y)) for x, y in VOTES.items()]
                    plurality.sort(key=lambda x: x[1])
                    votee, value = plurality.pop()
                    max_value = value
                    # Fetch all of the highest ties, exit out if we find someone lower
                    # If everyone is tied, then at some point plurality will be empty,
                    # but the values will still be at the max. Everything's fine, just break
                    while value == max_value:
                        voting.append(votee)
                        if not plurality:
                            break
                        votee, value = plurality.pop()

                if len(voting) == 1:
                    to_vote.append(voting[0])
                elif voting and kill_ties:
                    if set(voting) == set(get_players()): # killing everyone off? have you considered not doing that
                        abstaining = True
                    else:
                        to_vote.extend(voting)
                else:
                    abstaining = True

        if abstaining:
            for forced_abstainer in get_forced_abstains(var):
                if forced_abstainer not in ABSTAINS: # did not explicitly abstain
                    channels.Main.send(messages["player_meek_abstain"].format(forced_abstainer))

            abstain_evt = Event("abstain", {})
            abstain_evt.dispatch(var, ABSTAINS | get_forced_abstains(var))

            global ABSTAINED
            ABSTAINED = True
            channels.Main.send(messages["village_abstain"])

            from src.wolfgame import transition_night
            transition_night()

        if to_vote:
            global LYNCHED
            LYNCHED += len(to_vote) # track how many people we've lynched today

            if timeout:
                channels.Main.send(messages["sunset_lynch"])

            for votee in to_vote:
                voters = list(VOTES[votee])
                for forced_voter in get_forced_votes(var, votee):
                    if forced_voter not in voters: # did not explicitly vote
                        channels.Main.send(messages["impatient_vote"].format(forced_voter, votee))
                        voters.append(forced_voter) # they need to be counted as voting for them still

                if not try_lynch_immunity(var, votee):
                    lynch_evt = Event("lynch", {}, players=avail)
                    if lynch_evt.dispatch(var, votee, voters):
                        if var.ROLE_REVEAL in ("on", "team"):
                            rrole = get_reveal_role(votee)
                            an = "n" if rrole.startswith(("a", "e", "i", "o", "u")) else ""
                            lmsg = random.choice(messages["lynch_reveal"]).format(votee, an, rrole)
                        else:
                            lmsg = random.choice(messages["lynch_no_reveal"]).format(votee)
                        channels.Main.send(lmsg)
                        add_dying(var, votee, "villager", "lynch")

            kill_players(var, end_game=False) # FIXME

        elif timeout:
            channels.Main.send(messages["sunset"])

        from src.wolfgame import chk_win
        if chk_win():
            return # game ended, just exit out

        if timeout or LYNCHED >= num_lynches:
            from src.wolfgame import transition_night
            transition_night()
Exemplo n.º 34
0
    def shoot(var, wrapper, message):
        """Use this to fire off a bullet at someone in the day if you have bullets."""
        if not GUNNERS[wrapper.source]:
            wrapper.pm(messages["no_bullets"])
            return

        target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="gunner_target_self")
        if not target:
            return

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

        GUNNERS[wrapper.source] -= 1

        gun_evt = Event("gun_chances", {"hit": 0, "miss": 0, "headshot": 0})
        gun_evt.dispatch(var, wrapper.source, rolename)

        rand = random.random() # need to save it

        shoot_evt = Event("gun_shoot", {"hit": rand <= gun_evt.data["hit"], "kill": random.random() <= gun_evt.data["headshot"]})
        shoot_evt.dispatch(var, wrapper.source, target)

        realrole = get_main_role(target)
        targrole = get_reveal_role(target)

        if shoot_evt.data["hit"]:
            wrapper.send(messages["shoot_success"].format(wrapper.source, target))
            an = "n" if targrole.startswith(("a", "e", "i", "o", "u")) else ""
            if realrole in Wolf:
                if var.ROLE_REVEAL == "on":
                    wrapper.send(messages["gunner_victim_wolf_death"].format(target, an, targrole))
                else: # off and team
                    wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(target))
                add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim")
                if kill_players(var):
                    return
            elif shoot_evt.data["kill"]:
                accident = "accidentally "
                if gun_evt.data["headshot"] == 1: # would always headshot
                    accident = ""
                wrapper.send(messages["gunner_victim_villager_death"].format(target, accident))
                if var.ROLE_REVEAL in ("on", "team"):
                    wrapper.send(messages["gunner_victim_role"].format(an, targrole))
                add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim")
                if kill_players(var):
                    return
            else:
                wrapper.send(messages["gunner_victim_injured"].format(target))
                add_absent(var, target, "wounded")
                from src.votes import chk_decision
                from src.wolfgame import chk_win
                if not chk_win():
                    # game didn't immediately end due to injury, see if we should force through a vote
                    chk_decision(var)

        elif rand <= gun_evt.data["hit"] + gun_evt.data["miss"]:
            wrapper.send(messages["gunner_miss"].format(wrapper.source))
        else: # BOOM! your gun explodes, you're dead
            if var.ROLE_REVEAL in ("on", "team"):
                wrapper.send(messages["gunner_suicide"].format(wrapper.source, get_reveal_role(wrapper.source)))
            else:
                wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source))
            add_dying(var, wrapper.source, killer_role="villager", reason="gunner_suicide") # blame explosion on villager's shoddy gun construction or something
            kill_players(var)