This was put in to allow for custom messages if one couldn't target themselves. As such, an extra kwarg was added to pass in a custom message in such an event. It now returns None if they targeted themselves so the caller can fail gracefully.
168 lines
5.8 KiB
Python
168 lines
5.8 KiB
Python
import re
|
|
import random
|
|
from collections import defaultdict
|
|
|
|
import src.settings as var
|
|
from src.utilities import *
|
|
from src import users, channels, debuglog, errlog, plog
|
|
from src.functions import get_players, get_all_players, get_target, get_main_role
|
|
from src.decorators import command, event_listener
|
|
from src.messages import messages
|
|
from src.events import Event
|
|
|
|
KILLS = {} # type: Dict[users.User, users.User]
|
|
HUNTERS = set()
|
|
PASSED = set()
|
|
|
|
@command("kill", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("hunter",))
|
|
def hunter_kill(var, wrapper, message):
|
|
"""Kill someone once per game."""
|
|
if wrapper.source in HUNTERS and wrapper.source not in KILLS:
|
|
wrapper.pm(messages["hunter_already_killed"])
|
|
return
|
|
target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide")
|
|
if not target:
|
|
return
|
|
|
|
orig = target
|
|
evt = Event("targeted_command", {"target": target.nick, "misdirection": True, "exchange": True})
|
|
evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
|
|
if evt.prevent_default:
|
|
return
|
|
|
|
target = users._get(evt.data["target"]) # FIXME: Need to fix once targeted_command uses the new API
|
|
|
|
KILLS[wrapper.source] = target
|
|
HUNTERS.add(wrapper.source)
|
|
PASSED.discard(wrapper.source)
|
|
|
|
wrapper.pm(messages["player_kill"].format(orig))
|
|
|
|
debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
|
|
chk_nightdone(wrapper.client)
|
|
|
|
@command("retract", "r", chan=False, pm=True, playing=True, phases=("night",), roles=("hunter",))
|
|
def hunter_retract(var, wrapper, message):
|
|
"""Removes a hunter's kill selection."""
|
|
if wrapper.source not in KILLS and wrapper.source not in PASSED:
|
|
return
|
|
KILLS.pop(wrapper.source, None)
|
|
HUNTERS.discard(wrapper.source)
|
|
PASSED.discard(wrapper.source)
|
|
wrapper.pm(messages["retracted_kill"])
|
|
|
|
@command("pass", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("hunter",))
|
|
def hunter_pass(var, wrapper, message):
|
|
"""Do not use hunter's once-per-game kill tonight."""
|
|
if wrapper.source in HUNTERS and wrapper.source not in KILLS:
|
|
wrapper.pm(messages["hunter_already_killed"])
|
|
return
|
|
KILLS.pop(wrapper.source, None)
|
|
HUNTERS.discard(wrapper.source)
|
|
PASSED.add(wrapper.source)
|
|
wrapper.pm(messages["hunter_pass"])
|
|
|
|
debuglog("{0} (hunter) PASS".format(wrapper.source))
|
|
chk_nightdone(wrapper.client)
|
|
|
|
@event_listener("del_player")
|
|
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
|
HUNTERS.discard(user)
|
|
PASSED.discard(user)
|
|
KILLS.pop(user, None)
|
|
for h, v in list(KILLS.items()):
|
|
if v is user:
|
|
HUNTERS.discard(h)
|
|
h.send(messages["hunter_discard"])
|
|
del KILLS[h]
|
|
|
|
@event_listener("swap_player")
|
|
def on_swap(evt, var, old_user, user):
|
|
for a, b in list(KILLS.items()):
|
|
if a is old_user:
|
|
KILLS[user] = KILLS.pop(old_user)
|
|
if b is old_user:
|
|
KILLS[user] = KILLS.pop(old_user)
|
|
if old_user in HUNTERS:
|
|
HUNTERS.discard(old_user)
|
|
HUNTERS.add(user)
|
|
if old_user in PASSED:
|
|
PASSED.discard(old_user)
|
|
PASSED.add(user)
|
|
|
|
@event_listener("night_acted")
|
|
def on_acted(evt, var, user, actor):
|
|
if user in KILLS:
|
|
evt.data["acted"] = True
|
|
|
|
@event_listener("get_special")
|
|
def on_get_special(evt, var):
|
|
evt.data["special"].update(get_players(("hunter",)))
|
|
|
|
@event_listener("transition_day", priority=2)
|
|
def on_transition_day(evt, var):
|
|
for k, d in list(KILLS.items()):
|
|
evt.data["victims"].append(d)
|
|
evt.data["onlybywolves"].discard(d)
|
|
evt.data["killers"][d].append(k)
|
|
# important, otherwise our del_player listener lets hunter kill again
|
|
del KILLS[k]
|
|
|
|
@event_listener("exchange_roles")
|
|
def on_exchange(evt, var, actor, target, actor_role, target_role):
|
|
KILLS.pop(actor, None)
|
|
KILLS.pop(target, None)
|
|
HUNTERS.discard(actor)
|
|
HUNTERS.discard(target)
|
|
PASSED.discard(actor)
|
|
PASSED.discard(target)
|
|
|
|
@event_listener("chk_nightdone")
|
|
def on_chk_nightdone(evt, var):
|
|
evt.data["actedcount"] += len(KILLS) + len(PASSED)
|
|
hunter_users = get_all_players(("hunter",))
|
|
evt.data["nightroles"].extend([p for p in hunter_users if p not in HUNTERS or p in KILLS])
|
|
|
|
@event_listener("transition_night_end", priority=2)
|
|
def on_transition_night_end(evt, var):
|
|
ps = get_players()
|
|
for hunter in get_all_players(("hunter",)):
|
|
if hunter in HUNTERS:
|
|
continue # already killed
|
|
pl = ps[:]
|
|
random.shuffle(pl)
|
|
pl.remove(hunter)
|
|
to_send = "hunter_notify"
|
|
if hunter.prefers_simple():
|
|
to_send = "hunter_simple"
|
|
hunter.send(messages[to_send], "Players: " + ", ".join(p.nick for p in pl), sep="\n")
|
|
|
|
@event_listener("succubus_visit")
|
|
def on_succubus_visit(evt, cli, var, nick, victim):
|
|
user = users._get(victim) # FIXME
|
|
if user in KILLS and KILLS[user].nick in var.ROLES["succubus"]: # FIXME
|
|
user.send(messages["no_kill_succubus"].format(KILLS[user]))
|
|
del KILLS[user]
|
|
HUNTERS.discard(user)
|
|
|
|
@event_listener("begin_day")
|
|
def on_begin_day(evt, var):
|
|
KILLS.clear()
|
|
PASSED.clear()
|
|
|
|
@event_listener("reset")
|
|
def on_reset(evt, var):
|
|
KILLS.clear()
|
|
PASSED.clear()
|
|
HUNTERS.clear()
|
|
|
|
@event_listener("get_role_metadata")
|
|
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)
|
|
|
|
# vim: set sw=4 expandtab:
|