Overhaul succubus (first pass)
This commit is contained in:
parent
5331cda68f
commit
810d2ba3cc
@ -753,7 +753,6 @@
|
||||
"dullahan_die_success": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them. The village mourns the loss of a{2} \u0002{3}\u0002.",
|
||||
"dullahan_die_success_noreveal": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them.",
|
||||
"entranced_revert_win": "You are no longer entranced. \u0002Your win conditions have reset to normal.\u0002",
|
||||
"succubus_die_kill": "As the last remaining succubus dies, a foul curse causes {0} to wither away and die in front of the astonished village.",
|
||||
"player_sick": "You woke up today not feeling very well, you think it best to stay home for the remainder of the day and night.",
|
||||
"consecrating_no_vote": "You are consecrating someone today and cannot participate in the vote.",
|
||||
"illness_no_vote": "You are staying home due to your illness and cannot participate in the vote.",
|
||||
@ -763,7 +762,6 @@
|
||||
"blessed_notify_target": "You suddenly feel very safe.",
|
||||
"consecrate_fail": "\u0002{0}\u0002 is not currently playing or is not dead.",
|
||||
"consecrate_success": "You have consecrated the body of \u0002{0}\u0002.",
|
||||
"no_acting_on_succubus": "You may not {0} a succubus.",
|
||||
"coin_toss": "\u0002{0}\u0002 tosses a coin into the air...",
|
||||
"coin_land": "The coin lands on \u0002{0}\u0002.",
|
||||
"coin_choices": [
|
||||
|
@ -48,14 +48,13 @@ brokentotem = set() # type: Set[users.User]
|
||||
# 1. Expand var.TOTEM_ORDER and upate var.TOTEM_CHANCES to account for the new width
|
||||
# 2. Add the role to var.ROLE_GUIDE
|
||||
# 3. Add the role to whatever other holding vars are necessary based on what it does
|
||||
# 4. Setup initial variables and events with setup_variables(rolename, knows_totem, get_tags)
|
||||
# knows_totem is a bool and keyword-only. get_tags is a function in the form get_tags(var, totem)
|
||||
# and should return a set
|
||||
# 4. Setup initial variables and events with setup_variables(rolename, knows_totem)
|
||||
# knows_totem is a bool and keyword-only
|
||||
# 5. Implement custom events if the role does anything else beyond giving totems.
|
||||
#
|
||||
# Modifying this file to add new totems or new shaman roles is generally never required
|
||||
|
||||
def setup_variables(rolename, *, knows_totem, get_tags):
|
||||
def setup_variables(rolename, *, knows_totem):
|
||||
"""Setup role variables and shared events."""
|
||||
TOTEMS = UserDict() # type: Dict[users.User, str]
|
||||
LASTGIVEN = UserDict() # type: Dict[users.User, users.User]
|
||||
@ -178,14 +177,6 @@ def setup_variables(rolename, *, knows_totem, get_tags):
|
||||
evt.data["target_messages"].append(messages["shaman_totem"].format(actor_totem))
|
||||
TOTEMS[target] = actor_totem
|
||||
|
||||
@event_listener("succubus_visit")
|
||||
def on_succubus_visit(evt, var, succubus, target):
|
||||
if target in SHAMANS and SHAMANS[target][1] in get_all_players(("succubus",)):
|
||||
tags = get_tags(var, TOTEMS[target])
|
||||
if "beneficial" not in tags:
|
||||
target.send(messages["retract_totem_succubus"].format(SHAMANS[target][1]))
|
||||
del SHAMANS[target]
|
||||
|
||||
if knows_totem:
|
||||
@event_listener("myrole")
|
||||
def on_myrole(evt, var, user):
|
||||
@ -206,16 +197,14 @@ def get_totem_target(var, wrapper, message, lastgiven):
|
||||
|
||||
return target
|
||||
|
||||
def give_totem(var, wrapper, target, prefix, tags, role, msg):
|
||||
def give_totem(var, wrapper, target, prefix, role, msg):
|
||||
"""Give a totem to a player. Return the value of SHAMANS[user]."""
|
||||
|
||||
orig_target = target
|
||||
orig_role = get_main_role(orig_target)
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True},
|
||||
action="give a totem{0} to".format(msg))
|
||||
|
||||
if not evt.dispatch(var, "totem", wrapper.source, target, frozenset(tags)):
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
|
@ -41,7 +41,7 @@ def guard(cli, nick, chan, rest):
|
||||
|
||||
# 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, "guard", angel, target, frozenset({"beneficial"})):
|
||||
if not evt.dispatch(var, angel, target):
|
||||
return
|
||||
victim = evt.data["target"].nick
|
||||
GUARDED[nick] = victim
|
||||
|
@ -27,7 +27,7 @@ def target(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "target", wrapper.source, target, frozenset({"detrimental"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
target = evt.data["target"]
|
||||
|
||||
@ -132,17 +132,6 @@ def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
||||
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"])
|
||||
|
||||
@event_listener("succubus_visit")
|
||||
def on_succubus_visit(evt, var, actor, target):
|
||||
if target in TARGETED and TARGETED[target] in get_all_players(("succubus",)):
|
||||
msg = messages["no_target_succubus"].format(TARGETED[target])
|
||||
del TARGETED[target]
|
||||
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)
|
||||
TARGETED[target] = victim
|
||||
target.send(msg)
|
||||
|
||||
@event_listener("myrole")
|
||||
def on_myrole(evt, var, user):
|
||||
if user in get_all_players(("assassin",)):
|
||||
|
@ -26,7 +26,7 @@ def see(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "identify", wrapper.source, target, frozenset({"info", "immediate"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
|
@ -15,10 +15,7 @@ from src.events import Event
|
||||
|
||||
from src.roles._shaman_helper import setup_variables, get_totem_target, give_totem
|
||||
|
||||
def get_tags(var, totem):
|
||||
return set()
|
||||
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("crazed shaman", knows_totem=False, get_tags=get_tags)
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("crazed shaman", knows_totem=False)
|
||||
|
||||
@command("give", "totem", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("crazed shaman",))
|
||||
def crazed_shaman_totem(var, wrapper, message):
|
||||
@ -28,9 +25,7 @@ def crazed_shaman_totem(var, wrapper, message):
|
||||
if not target:
|
||||
return
|
||||
|
||||
totem = TOTEMS[wrapper.source]
|
||||
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", tags=get_tags(var, totem), role="crazed shaman", msg="")
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", role="crazed shaman", msg="")
|
||||
|
||||
@event_listener("player_win")
|
||||
def on_player_win(evt, var, user, role, winner, survived):
|
||||
@ -47,16 +42,11 @@ def on_transition_day_begin(evt, var):
|
||||
if shaman in LASTGIVEN:
|
||||
if LASTGIVEN[shaman] in ps:
|
||||
ps.remove(LASTGIVEN[shaman])
|
||||
levt = Event("get_random_totem_targets", {"targets": ps})
|
||||
levt.dispatch(var, shaman)
|
||||
ps = levt.data["targets"]
|
||||
if ps:
|
||||
target = random.choice(ps)
|
||||
dispatcher = MessageDispatcher(shaman, shaman)
|
||||
|
||||
tags = get_tags(var, TOTEMS[shaman])
|
||||
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], tags=tags, role="crazed shaman", msg="")
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], role="crazed shaman", msg="")
|
||||
else:
|
||||
LASTGIVEN[shaman] = None
|
||||
elif shaman not in SHAMANS:
|
||||
|
@ -25,7 +25,7 @@ def investigate(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "identify", wrapper.source, target, frozenset({"info", "immediate"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
|
@ -31,7 +31,7 @@ def see(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "see", wrapper.source, target, frozenset({"detrimental", "immediate"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
|
||||
|
@ -28,7 +28,7 @@ def dullahan_kill(var, wrapper, message):
|
||||
|
||||
orig = target
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "kill", wrapper.source, target, frozenset({"detrimental"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target = evt.data["target"]
|
||||
@ -186,12 +186,10 @@ def on_role_assignment(evt, var, gamemode, pl):
|
||||
|
||||
@event_listener("succubus_visit")
|
||||
def on_succubus_visit(evt, var, succubus, target):
|
||||
if target in TARGETS and succubus in TARGETS[target]:
|
||||
TARGETS[target].remove(succubus)
|
||||
succubi = get_all_players(("succubus",))
|
||||
if target in TARGETS and TARGETS[target].intersection(succubi):
|
||||
TARGETS[target].difference_update(succubi)
|
||||
target.send(messages["dullahan_no_kill_succubus"])
|
||||
if target in KILLS and KILLS[target] in get_all_players(("succubus",)):
|
||||
target.send(messages["no_kill_succubus"].format(KILLS[target]))
|
||||
del KILLS[target]
|
||||
|
||||
@event_listener("myrole")
|
||||
def on_myrole(evt, var, user):
|
||||
|
@ -28,7 +28,7 @@ def hvisit(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "visit", wrapper.source, target, frozenset({"immediate"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target = evt.data["target"]
|
||||
|
@ -26,7 +26,7 @@ def hunter_kill(var, wrapper, message):
|
||||
|
||||
orig = target
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "kill", wrapper.source, target, frozenset({"detrimental"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
|
||||
@ -125,13 +125,6 @@ def on_transition_night_end(evt, var):
|
||||
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, var, succubus, target):
|
||||
if target in KILLS and KILLS[target] in get_all_players(("succubus",)):
|
||||
target.send(messages["no_kill_succubus"].format(KILLS[target]))
|
||||
del KILLS[target]
|
||||
HUNTERS.discard(target)
|
||||
|
||||
@event_listener("begin_day")
|
||||
def on_begin_day(evt, var):
|
||||
KILLS.clear()
|
||||
|
@ -38,13 +38,13 @@ def investigate(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target1, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "identify", wrapper.source, target1, frozenset({"info", "immediate"}))
|
||||
evt.dispatch(var, wrapper.source, target1)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target1 = evt.data["target"]
|
||||
|
||||
evt = Event("targeted_command", {"target": target2, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "identify", wrapper.source, target2, frozenset({"info", "immediate"}))
|
||||
evt.dispatch(var, wrapper.source, target2)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target2 = evt.data["target"]
|
||||
|
@ -26,7 +26,7 @@ def see(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "see", wrapper.source, target, frozenset({"info", "immediate"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
|
@ -43,14 +43,14 @@ def charm(var, wrapper, message):
|
||||
orig2 = target2
|
||||
|
||||
evt1 = Event("targeted_command", {"target": target1, "misdirection": True, "exchange": True})
|
||||
evt1.dispatch(var, "charm", wrapper.source, target1, frozenset({"detrimental"}))
|
||||
evt1.dispatch(var, wrapper.source, target1)
|
||||
if evt1.prevent_default:
|
||||
return
|
||||
target1 = evt1.data["target"]
|
||||
|
||||
if target2 is not None:
|
||||
evt2 = Event("targeted_command", {"target": target2, "misdirection": True, "exchange": True})
|
||||
evt2.dispatch(var, "charm", wrapper.source, target2, frozenset({"detrimental"}))
|
||||
evt2.dispatch(var, wrapper.source, target2)
|
||||
if evt2.prevent_default:
|
||||
return
|
||||
target2 = evt2.data["target"]
|
||||
|
@ -26,7 +26,7 @@ def see(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "see", wrapper.source, target, frozenset({"info", "immediate"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
|
@ -15,13 +15,7 @@ from src.events import Event
|
||||
|
||||
from src.roles._shaman_helper import setup_variables, get_totem_target, give_totem
|
||||
|
||||
def get_tags(var, totem):
|
||||
tags = set()
|
||||
if totem in var.BENEFICIAL_TOTEMS:
|
||||
tags.add("beneficial")
|
||||
return tags
|
||||
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("shaman", knows_totem=True, get_tags=get_tags)
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("shaman", knows_totem=True)
|
||||
|
||||
@command("give", "totem", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("shaman",))
|
||||
def shaman_totem(var, wrapper, message):
|
||||
@ -31,9 +25,7 @@ def shaman_totem(var, wrapper, message):
|
||||
if not target:
|
||||
return
|
||||
|
||||
totem = TOTEMS[wrapper.source]
|
||||
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", tags=get_tags(var, totem), role="shaman", msg=" of {0}".format(totem))
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", role="shaman", msg=" of {0}".format(TOTEMS[wrapper.source]))
|
||||
|
||||
@event_listener("transition_day_begin", priority=4)
|
||||
def on_transition_day_begin(evt, var):
|
||||
@ -45,16 +37,11 @@ def on_transition_day_begin(evt, var):
|
||||
if shaman in LASTGIVEN:
|
||||
if LASTGIVEN[shaman] in ps:
|
||||
ps.remove(LASTGIVEN[shaman])
|
||||
levt = Event("get_random_totem_targets", {"targets": ps})
|
||||
levt.dispatch(var, shaman)
|
||||
ps = levt.data["targets"]
|
||||
if ps:
|
||||
target = random.choice(ps)
|
||||
dispatcher = MessageDispatcher(shaman, shaman)
|
||||
|
||||
tags = get_tags(var, TOTEMS[shaman])
|
||||
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], tags=tags, role="shaman", msg=" of {0}".format(TOTEMS[shaman]))
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], role="shaman", msg=" of {0}".format(TOTEMS[shaman]))
|
||||
else:
|
||||
LASTGIVEN[shaman] = None
|
||||
elif shaman not in SHAMANS:
|
||||
|
@ -14,7 +14,6 @@ from src.messages import messages
|
||||
from src.events import Event
|
||||
|
||||
ENTRANCED = UserSet() # type: Set[users.User]
|
||||
ENTRANCED_DYING = UserSet() # type: Set[users.User]
|
||||
VISITED = UserDict() # type: Dict[users.User, users.User]
|
||||
PASSED = UserSet() # type: Set[users.User]
|
||||
ALL_SUCC_IDLE = True
|
||||
@ -32,7 +31,7 @@ def hvisit(var, wrapper, message):
|
||||
return
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": False})
|
||||
evt.dispatch(var, "visit", wrapper.source, target, frozenset({"detrimental", "immediate"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target = evt.data["target"]
|
||||
@ -55,16 +54,6 @@ def hvisit(var, wrapper, message):
|
||||
revt = Event("succubus_visit", {})
|
||||
revt.dispatch(var, wrapper.source, target)
|
||||
|
||||
# TODO: split these into hag and alpha wolf when they are split off
|
||||
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)))
|
||||
|
||||
@command("pass", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("succubus",))
|
||||
@ -85,58 +74,6 @@ def on_harlot_visit(evt, var, harlot, victim):
|
||||
victim.send(messages["succubus_harlot_success"].format(harlot))
|
||||
ENTRANCED.add(harlot)
|
||||
|
||||
@event_listener("get_random_totem_targets")
|
||||
def on_get_random_totem_targets(evt, var, shaman):
|
||||
if shaman in ENTRANCED:
|
||||
for succubus in get_all_players(("succubus",)):
|
||||
if succubus in evt.data["targets"]:
|
||||
evt.data["targets"].remove(succubus)
|
||||
|
||||
@event_listener("chk_decision")
|
||||
def on_chk_decision(evt, var, force):
|
||||
for votee, voters in evt.data["votelist"].items():
|
||||
if votee in get_all_players(("succubus",)):
|
||||
for vtr in ENTRANCED:
|
||||
if vtr in voters:
|
||||
evt.data["numvotes"][votee] -= evt.data["weights"][votee][vtr]
|
||||
evt.data["weights"][votee][vtr] = 0
|
||||
|
||||
def _kill_entranced_voters(var, votelist, not_lynching, votee):
|
||||
voters = set(itertools.chain(*votelist.values()))
|
||||
if not get_all_players(("succubus",)) & (voters | not_lynching):
|
||||
# none of the succubi voted (or there aren't any succubi), so short-circuit
|
||||
return
|
||||
# kill off everyone entranced that did not follow one of the succubi's votes or abstain
|
||||
# unless a succubus successfully voted the target, then people that didn't follow are spared
|
||||
for x in ENTRANCED:
|
||||
if x.nick not in var.DEAD:
|
||||
ENTRANCED_DYING.add(x)
|
||||
|
||||
for other_votee, other_voters in votelist.items():
|
||||
if get_all_players(("succubus",)) & set(other_voters):
|
||||
if votee is other_votee:
|
||||
ENTRANCED_DYING.clear()
|
||||
return
|
||||
|
||||
ENTRANCED_DYING.difference_update(other_voters)
|
||||
|
||||
if get_all_players(("succubus",)) & not_lynching:
|
||||
if votee is None:
|
||||
ENTRANCED_DYING.clear()
|
||||
return
|
||||
|
||||
ENTRANCED_DYING.difference_update(not_lynching)
|
||||
|
||||
@event_listener("chk_decision_lynch", priority=5)
|
||||
def on_chk_decision_lynch(evt, var, voters):
|
||||
# a different event may override the original votee, but people voting along with succubus
|
||||
# won't necessarily know that, so base whether or not they risk death on the person originally voted
|
||||
_kill_entranced_voters(var, evt.params.votelist, evt.params.not_lynching, evt.params.original_votee)
|
||||
|
||||
@event_listener("chk_decision_abstain")
|
||||
def on_chk_decision_abstain(evt, var, not_lynching):
|
||||
_kill_entranced_voters(var, evt.params.votelist, not_lynching, None)
|
||||
|
||||
# entranced logic should run after team wins have already been determined (aka run last)
|
||||
@event_listener("player_win", priority=6)
|
||||
def on_player_win(evt, var, user, role, winner, survived):
|
||||
@ -153,15 +90,23 @@ def on_player_win(evt, var, user, role, winner, survived):
|
||||
def on_chk_win(evt, var, rolemap, mainroles, lpl, lwolves, lrealwolves):
|
||||
lsuccubi = len(rolemap.get("succubus", ()))
|
||||
lentranced = len([x for x in ENTRANCED if x.nick not in var.DEAD])
|
||||
if lsuccubi and var.PHASE == "day" and lpl - lsuccubi == lentranced:
|
||||
if var.PHASE == "day" and lpl - lsuccubi == lentranced:
|
||||
evt.data["winner"] = "succubi"
|
||||
evt.data["message"] = messages["succubus_win"].format(plural("succubus", lsuccubi), plural("has", lsuccubi), plural("master's", lsuccubi))
|
||||
|
||||
@event_listener("can_exchange")
|
||||
def on_can_exchange(evt, var, actor, target):
|
||||
if actor in get_all_players(("succubus",)) or target in get_all_players(("succubus",)):
|
||||
evt.prevent_default = True
|
||||
evt.stop_processing = True
|
||||
@event_listener("exchange_roles")
|
||||
def on_exchange_roles(evt, var, actor, target, actor_role, target_role):
|
||||
del VISITED[:actor:]
|
||||
del VISITED[:target:]
|
||||
PASSED.discard(actor)
|
||||
PASSED.discard(target)
|
||||
|
||||
if actor in ENTRANCED:
|
||||
ENTRANCED.remove(actor)
|
||||
actor.send(messages["no_longer_entranced"])
|
||||
if target in ENTRANCED:
|
||||
ENTRANCED.remove(target)
|
||||
target.send(messages["no_longer_entranced"])
|
||||
|
||||
@event_listener("del_player")
|
||||
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
||||
@ -173,13 +118,10 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
||||
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)
|
||||
# if all succubi idled out (every last one of them), un-entrance people
|
||||
# death_triggers is False for an idle-out, so we use that to determine which it is
|
||||
if death_triggers:
|
||||
ALL_SUCC_IDLE = False
|
||||
@ -189,36 +131,6 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
||||
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()
|
||||
|
||||
@event_listener("transition_day_resolve", priority=1)
|
||||
def on_transition_day_resolve(evt, var, victim):
|
||||
@ -255,17 +167,6 @@ def on_chk_nightdone(evt, var):
|
||||
evt.data["actedcount"] += len(VISITED) + len(PASSED)
|
||||
evt.data["nightroles"].extend(get_all_players(("succubus",)))
|
||||
|
||||
@event_listener("targeted_command")
|
||||
def on_targeted_command(evt, var, name, actor, orig_target, tags):
|
||||
if "beneficial" not in tags and actor in ENTRANCED and evt.data["target"] in get_all_players(("succubus",)):
|
||||
try:
|
||||
what = evt.params.action
|
||||
except AttributeError:
|
||||
what = name
|
||||
actor.send(messages["no_acting_on_succubus"].format(what))
|
||||
evt.stop_processing = True
|
||||
evt.prevent_default = True
|
||||
|
||||
@event_listener("transition_night_end", priority=2)
|
||||
def on_transition_night_end(evt, var):
|
||||
succubi = get_all_players(("succubus",))
|
||||
@ -287,17 +188,8 @@ def on_transition_night_end(evt, var):
|
||||
@event_listener("begin_day")
|
||||
def on_begin_day(evt, var):
|
||||
VISITED.clear()
|
||||
ENTRANCED_DYING.clear()
|
||||
PASSED.clear()
|
||||
|
||||
@event_listener("transition_day", priority=2)
|
||||
def on_transition_day(evt, var):
|
||||
for v in ENTRANCED_DYING:
|
||||
var.DYING.add(v) # indicate that the death bypasses protections
|
||||
evt.data["victims"].append(v)
|
||||
evt.data["onlybywolves"].discard(v)
|
||||
# we do not add to killers as retribution totem should not work on entranced not following succubus
|
||||
|
||||
@event_listener("get_special")
|
||||
def on_get_special(evt, var):
|
||||
evt.data["win_stealers"].update(get_players(("succubus",)))
|
||||
@ -318,7 +210,6 @@ def on_reset(evt, var):
|
||||
global ALL_SUCC_IDLE
|
||||
ALL_SUCC_IDLE = True
|
||||
ENTRANCED.clear()
|
||||
ENTRANCED_DYING.clear()
|
||||
VISITED.clear()
|
||||
PASSED.clear()
|
||||
|
||||
@ -327,7 +218,4 @@ def on_revealroles(evt, var, wrapper):
|
||||
if ENTRANCED:
|
||||
evt.data["output"].append("\u0002entranced players\u0002: {0}".format(", ".join(p.nick for p in ENTRANCED)))
|
||||
|
||||
if ENTRANCED_DYING:
|
||||
evt.data["output"].append("\u0002dying entranced players\u0002: {0}".format(", ".join(p.nick for p in ENTRANCED_DYING)))
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -40,7 +40,7 @@ def vg_kill(var, wrapper, message):
|
||||
|
||||
orig = target
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": False})
|
||||
evt.dispatch(var, "kill", wrapper.source, target, frozenset({"detrimental"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target = evt.data["target"]
|
||||
|
@ -21,7 +21,7 @@ def vigilante_kill(var, wrapper, message):
|
||||
|
||||
orig = target
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "kill", wrapper.source, target, frozenset({"detrimental"}))
|
||||
evt.dispatch(var, wrapper.source, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
target = evt.data["target"]
|
||||
@ -107,12 +107,6 @@ def on_transition_night_end(evt, var):
|
||||
to_send = "vigilante_simple"
|
||||
vigilante.send(messages[to_send], "Players: " + ", ".join(p.nick for p in pl), sep="\n")
|
||||
|
||||
@event_listener("succubus_visit")
|
||||
def on_succubus_visit(evt, var, succubus, target):
|
||||
if target in KILLS and KILLS[target] in get_all_players(("succubus",)):
|
||||
target.send(messages["no_kill_succubus"].format(KILLS[target]))
|
||||
del KILLS[target]
|
||||
|
||||
@event_listener("begin_day")
|
||||
def on_begin_day(evt, var):
|
||||
KILLS.clear()
|
||||
|
@ -74,7 +74,7 @@ def wolf_kill(cli, nick, chan, rest):
|
||||
target = users._get(victim) # FIXME
|
||||
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
evt.dispatch(var, "kill", wolf, target, frozenset({"detrimental"}))
|
||||
evt.dispatch(var, wolf, target)
|
||||
if evt.prevent_default:
|
||||
return
|
||||
victim = evt.data["target"].nick
|
||||
@ -437,16 +437,6 @@ def on_transition_night_end(evt, var):
|
||||
if var.ALPHA_ENABLED and role == "alpha wolf" and wolf.nick not in var.ALPHA_WOLVES: # FIXME: Fix once var.ALPHA_WOLVES holds User instances
|
||||
wolf.send(messages["wolf_bite"])
|
||||
|
||||
@event_listener("succubus_visit")
|
||||
def on_succubus_visit(evt, var, succubus, target):
|
||||
if get_all_players(("succubus",)).intersection(users._get(x) for x in KILLS.get(target.nick, ())): # FIXME: once KILLS holds User instances
|
||||
for s in get_all_players(("succubus",)):
|
||||
if s.nick in KILLS[target.nick]:
|
||||
target.send(messages["no_kill_succubus"].format(succubus))
|
||||
KILLS[target.nick].remove(s.nick)
|
||||
if not KILLS[target.nick]:
|
||||
del KILLS[target.nick]
|
||||
|
||||
@event_listener("begin_day")
|
||||
def on_begin_day(evt, var):
|
||||
KILLS.clear()
|
||||
|
@ -15,13 +15,7 @@ from src.events import Event
|
||||
|
||||
from src.roles._shaman_helper import setup_variables, get_totem_target, give_totem
|
||||
|
||||
def get_tags(var, totem):
|
||||
tags = set()
|
||||
if totem in var.BENEFICIAL_TOTEMS:
|
||||
tags.add("beneficial")
|
||||
return tags
|
||||
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("wolf shaman", knows_totem=True, get_tags=get_tags)
|
||||
TOTEMS, LASTGIVEN, SHAMANS = setup_variables("wolf shaman", knows_totem=True)
|
||||
|
||||
@command("give", "totem", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("wolf shaman",))
|
||||
def wolf_shaman_totem(var, wrapper, message):
|
||||
@ -31,9 +25,7 @@ def wolf_shaman_totem(var, wrapper, message):
|
||||
if not target:
|
||||
return
|
||||
|
||||
totem = TOTEMS[wrapper.source]
|
||||
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", tags=get_tags(var, totem), role="wolf shaman", msg=" of {0}".format(totem))
|
||||
SHAMANS[wrapper.source] = give_totem(var, wrapper, target, prefix="You", role="wolf shaman", msg=" of {0}".format(TOTEMS[wrapper.source]))
|
||||
|
||||
relay_wolfchat_command(wrapper.client, wrapper.source.nick, messages["shaman_wolfchat"].format(wrapper.source, target), ("wolf shaman",), is_wolf_command=True)
|
||||
|
||||
@ -47,16 +39,11 @@ def on_transition_day_begin(evt, var):
|
||||
if shaman in LASTGIVEN:
|
||||
if LASTGIVEN[shaman] in ps:
|
||||
ps.remove(LASTGIVEN[shaman])
|
||||
levt = Event("get_random_totem_targets", {"targets": ps})
|
||||
levt.dispatch(var, shaman)
|
||||
ps = levt.data["targets"]
|
||||
if ps:
|
||||
target = random.choice(ps)
|
||||
dispatcher = MessageDispatcher(shaman, shaman)
|
||||
|
||||
tags = get_tags(var, TOTEMS[shaman])
|
||||
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], tags=tags, role="wolf shaman", msg=" of {0}".format(TOTEMS[shaman]))
|
||||
SHAMANS[shaman] = give_totem(var, dispatcher, target, prefix=messages["random_totem_prefix"], role="wolf shaman", msg=" of {0}".format(TOTEMS[shaman]))
|
||||
relay_wolfchat_command(shaman.client, shaman.nick, messages["shaman_wolfchat"].format(shaman, target), ("wolf shaman",), is_wolf_command=True)
|
||||
else:
|
||||
LASTGIVEN[shaman] = None
|
||||
|
@ -3717,9 +3717,6 @@ def check_exchange(cli, actor, nick):
|
||||
user = users._get(actor) # FIXME
|
||||
target = users._get(nick) # FIXME
|
||||
|
||||
event = Event("can_exchange", {})
|
||||
if not event.dispatch(var, user, target):
|
||||
return False # some roles such as succubus cannot be affected by exchange totem
|
||||
if nick in var.EXCHANGED:
|
||||
var.EXCHANGED.remove(nick)
|
||||
actor_role = get_role(actor)
|
||||
@ -3926,7 +3923,7 @@ def shoot(var, wrapper, message):
|
||||
|
||||
# get actual victim
|
||||
evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True})
|
||||
if not evt.dispatch(var, "shoot", wrapper.source, target, frozenset({"detrimental"})):
|
||||
if not evt.dispatch(var, wrapper.source, target):
|
||||
return
|
||||
|
||||
target = evt.data["target"]
|
||||
@ -3995,12 +3992,6 @@ def shoot(var, wrapper, message):
|
||||
wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source))
|
||||
del_player(wrapper.source, killer_role="villager") # blame explosion on villager's shoddy gun construction or something
|
||||
|
||||
def is_safe(nick, victim): # replace calls to this with targeted_command event when splitting roles
|
||||
from src.roles import succubus
|
||||
user = users._get(nick) # FIXME
|
||||
target = users._get(victim) # FIXME
|
||||
return user in succubus.ENTRANCED and target in get_all_players(("succubus",))
|
||||
|
||||
@cmd("bless", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("priest",))
|
||||
def bless(cli, nick, chan, rest):
|
||||
"""Bless a player, preventing them from being killed for the remainder of the game."""
|
||||
@ -4083,9 +4074,6 @@ def observe(cli, nick, chan, rest):
|
||||
else:
|
||||
pm(cli, nick, messages["no_observe_wolf"])
|
||||
return
|
||||
if is_safe(nick, victim):
|
||||
pm(cli, nick, messages["no_acting_on_succubus"].format("observe"))
|
||||
return
|
||||
victim = choose_target(nick, victim)
|
||||
if check_exchange(cli, nick, victim):
|
||||
return
|
||||
@ -4263,9 +4251,6 @@ def bite_cmd(cli, nick, chan, rest):
|
||||
if not victim:
|
||||
pm(cli, nick, messages["bite_error"])
|
||||
return
|
||||
if is_safe(nick, victim):
|
||||
pm(cli, nick, messages["no_acting_on_succubus"].format("bite"))
|
||||
return
|
||||
|
||||
vrole = get_role(victim)
|
||||
actual = choose_target(nick, victim)
|
||||
@ -4351,10 +4336,6 @@ def hex_target(cli, nick, chan, rest):
|
||||
pm(cli, nick, messages["no_multiple_hex"].format(victim))
|
||||
return
|
||||
|
||||
if is_safe(nick, victim):
|
||||
pm(cli, nick, messages["no_acting_on_succubus"].format("hex"))
|
||||
return
|
||||
|
||||
victim = choose_target(nick, victim)
|
||||
if in_wolflist(nick, victim):
|
||||
pm(cli, nick, messages["no_hex_wolf"])
|
||||
@ -4386,10 +4367,6 @@ def curse(cli, nick, chan, rest):
|
||||
victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
|
||||
if not victim:
|
||||
return
|
||||
if is_safe(nick, victim):
|
||||
pm(cli, nick, messages["no_acting_on_succubus"].format("curse"))
|
||||
return
|
||||
|
||||
# There may actually be valid strategy in cursing other wolfteam members,
|
||||
# but for now it is not allowed. If someone seems suspicious and shows as
|
||||
# villager across multiple nights, safes can use that as a tell that the
|
||||
@ -4461,7 +4438,7 @@ def clone(cli, nick, chan, rest):
|
||||
var.ROLE_COMMAND_EXCEPTIONS.add("clone")
|
||||
|
||||
@event_listener("targeted_command", priority=9)
|
||||
def on_targeted_command(evt, var, name, actor, orig_target, tags):
|
||||
def on_targeted_command(evt, var, actor, orig_target):
|
||||
if evt.data["misdirection"]:
|
||||
evt.data["target"] = users._get(choose_target(actor.nick, evt.data["target"].nick)) # FIXME
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user