Split blessed and cursed villager

This commit is contained in:
skizzerz 2016-09-13 16:35:54 -05:00
parent f5d510374a
commit 01dfdc7ac4
8 changed files with 281 additions and 144 deletions

View File

@ -241,6 +241,24 @@ def on_transition_night_end(evt, cli, var):
pm(cli, gangel, messages["guardian_simple"]) # !simple
pm(cli, gangel, "Players: " + ", ".join(pl))
@event_listener("assassinate")
def on_assassinate(evt, cli, var, nick, target, prot):
if prot == "angel" and var.GAMEPHASE == "night":
var.ACTIVE_PROTECTIONS[target].remove("angel")
evt.prevent_default = True
evt.stop_propagation = True
cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "angel"].format(nick, target))
elif prot == "bodyguard":
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
evt.prevent_default = True
evt.stop_propagation = True
for bg in var.ROLES["bodyguard"]:
if GUARDED.get(bg) == target:
cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "bodyguard"].format(nick, target, bg))
evt.params.del_player(cli, bg, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
evt.data["pl"] = evt.params.refresh_pl(pl)
break
@event_listener("begin_day")
def on_begin_day(evt, cli, var):
PASSED.clear()

91
src/roles/blessed.py Normal file
View File

@ -0,0 +1,91 @@
import re
import random
import itertools
import math
from collections import defaultdict
import botconfig
import src.settings as var
from src.utilities import *
from src import debuglog, errlog, plog
from src.decorators import cmd, event_listener
from src.messages import messages
from src.events import Event
# TODO: some additional stuff with blessed villager has not been split yet,
# notably the interactions with assassin and mad scientist, need to split those out too
# as part of splitting assassin/MS (new events will be required)
@event_listener("transition_day", priority=4.3)
def on_transition_day(evt, cli, var):
pl = list_players()
vs = set(evt.data["victims"])
for v in pl:
if v in vs:
if v in var.DYING:
continue
if v in var.ROLES["blessed villager"]:
evt.data["numkills"][v] -= 1
if evt.data["numkills"][v] >= 0:
evt.data["killers"][v].pop(0)
if evt.data["numkills"][v] <= 0 and v not in evt.data["protected"]:
evt.data["protected"][v] = "blessing"
elif evt.data["numkills"][v] <= 0:
var.ACTIVE_PROTECTIONS[v].append("blessing")
elif v in var.ROLES["blessed villager"]:
var.ACTIVE_PROTECTIONS[v].append("blessing")
@event_listener("transition_day_resolve", priority=2)
def on_transition_day_resolve(evt, cli, var, victim):
# TODO: remove these checks once everything is split
# right now they're needed because otherwise protection may fire off even if the person isn't home
# that will not be an issue once everything is using the event
if victim in var.ROLES["harlot"] | var.ROLES["succubus"] and var.HVISITED.get(victim) and victim not in evt.data["dead"] and victim in evt.data["onlybywolves"]:
return
# END checks to remove
if evt.data["protected"].get(victim) == "blessing":
# don't play any special message for a blessed target, this means in a game with priest and monster it's not really possible
# for wolves to tell which is which. May want to change that in the future to be more obvious to wolves since there's not really
# any good reason to hide that info from them. In any case, we don't want to say the blessed person was attacked to the channel
evt.stop_propagation = True
evt.prevent_default = True
@event_listener("transition_night_end", priority=5)
def on_transition_night_end(evt, cli, var):
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
for blessed in var.ROLES["blessed villager"]:
if blessed in var.PLAYERS and not is_user_simple(blessed):
pm(cli, blessed, messages["blessed_notify"])
else:
pm(cli, blessed, messages["blessed_simple"])
@event_listener("desperation_totem")
def on_desperation(evt, cli, var, votee, target, prot):
if prot == "blessing":
var.ACTIVE_PROTECTIONS[target].remove("blessing")
evt.prevent_default = True
evt.stop_propagation = True
@event_listener("retribution_totem")
def on_retribution(evt, cli, var, victim, loser, prot):
if prot == "blessing":
var.ACTIVE_PROTECTIONS[target].remove("blessing")
evt.prevent_default = True
evt.stop_propagation = True
@event_listener("assassinate")
def on_assassinate(evt, cli, var, nick, target, prot):
if prot == "blessing":
var.ACTIVE_PROTECTIONS[target].remove("blessing")
evt.prevent_default = True
evt.stop_propagation = True
# don't message the channel whenever a blessing blocks a kill, but *do* let the killer know so they don't try to report it as a bug
pm(cli, nick, messages["assassin_fail_blessed"].format(target))
@event_listener("myrole")
def on_myrole(evt, cli, var, nick):
if nick in var.ROLES["blessed villager"]:
evt.data["messages"].append(messages["blessed_simple"])
# vim: set sw=4 expandtab:

25
src/roles/cursed.py Normal file
View File

@ -0,0 +1,25 @@
import re
import random
import itertools
import math
from collections import defaultdict
import botconfig
import src.settings as var
from src.utilities import *
from src import debuglog, errlog, plog
from src.decorators import cmd, event_listener
from src.messages import messages
from src.events import Event
@event_listener("see")
def on_see(evt, cli, var, nick, victim):
if nick in var.ROLES["cursed villager"]:
evt.data["role"] = "wolf"
@event_listener("wolflist")
def on_wolflist(evt, cli, var, nick, wolf):
if nick in var.ROLES["cursed villager"]:
evt.data["tags"].add("cursed")
# vim: set sw=4 expandtab:

View File

@ -1,7 +1,7 @@
import math
import re
import random
from collections import defaultdict
from collections import defaultdict, deque
import src.settings as var
from src.utilities import *
@ -77,35 +77,30 @@ def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers):
targets = TARGETS[nick] & set(pl)
if targets:
target = random.choice(list(targets))
if "totem" in var.ACTIVE_PROTECTIONS[target]:
var.ACTIVE_PROTECTIONS[target].remove("totem")
cli.msg(botconfig.CHANNEL, messages["dullahan_die_totem"].format(nick, target))
elif "angel" in var.ACTIVE_PROTECTIONS[target]:
var.ACTIVE_PROTECTIONS[target].remove("angel")
cli.msg(botconfig.CHANNEL, messages["dullahan_die_angel"].format(nick, target))
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target]:
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
for bg in var.ROLES["bodyguard"]:
if var.GUARDED.get(bg) == target:
cli.msg(botconfig.CHANNEL, messages["dullahan_die_bodyguard"].format(nick, target, bg))
evt.params.del_player(cli, bg, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
evt.data["pl"] = evt.params.refresh_pl(pl)
break
elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]):
if "blessing" in var.ACTIVE_PROTECTIONS[target]:
var.ACTIVE_PROTECTIONS[target].remove("blessing")
# don't message the channel whenever a blessing blocks a kill, but *do* let the dullahan know so they don't try to report it as a bug
pm(cli, nick, messages["assassin_fail_blessed"].format(target))
prots = deque(var.ACTIVE_PROTECTIONS[target])
aevt = Event("assassinate", {"pl": evt.data["pl"]},
del_player=evt.params.del_player,
deadlist=evt.params.deadlist,
original=evt.params.original,
refresh_pl=evt.params.refresh_pl,
message_prefix="dullahan_die_")
while len(prots) > 0:
# an event can read the current active protection and cancel the totem
# if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
# so that it cannot be used again (if the protection is meant to be usable once-only)
if not aevt.dispatch(cli, var, nick, target, prots[0]):
evt.data["pl"] = aevt.data["pl"]
return
prots.popleft()
if var.ROLE_REVEAL in ("on", "team"):
role = get_reveal_role(target)
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success"].format(nick, target, an, role))
else:
if var.ROLE_REVEAL in ("on", "team"):
role = get_reveal_role(target)
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success"].format(nick, target, an, role))
else:
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success_noreveal"].format(nick, target))
debuglog("{0} ({1}) DULLAHAN ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
evt.params.del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
evt.data["pl"] = evt.params.refresh_pl(pl)
cli.msg(botconfig.CHANNEL, messages["dullahan_die_success_noreveal"].format(nick, target))
debuglog("{0} ({1}) DULLAHAN ASSASSINATE: {2} ({3})".format(nick, nickrole, target, get_role(target)))
evt.params.del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
evt.data["pl"] = evt.params.refresh_pl(pl)
@event_listener("rename_player")
def on_rename(evt, cli, var, prefix, nick):

View File

@ -33,7 +33,7 @@ def see(cli, nick, chan, rest):
victimrole = get_role(victim)
if role != "augur":
if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT) or victim in var.ROLES["cursed villager"]:
if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT):
victimrole = "wolf"
elif victimrole in var.SEEN_DEFAULT:
victimrole = var.DEFAULT_ROLE

View File

@ -1,7 +1,7 @@
import re
import random
import itertools
from collections import defaultdict
from collections import defaultdict, deque
import botconfig
import src.settings as var
@ -275,11 +275,16 @@ def on_chk_decision_lynch5(evt, cli, var, 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]
# TODO: instead of desperation_totem event to accomodate blessed villager, base on var.ACTIVE_PROTECTIONS
# this means that prot totem, GA, and bodyguard would have a shot to block this too
# and so that blessed villager doesn't double-dip (like if they were targeted that past night)
desp_evt = Event("desperation_totem", {})
if target != votee and desp_evt.dispatch(cli, var, votee, target) and target not in var.ROLES["blessed villager"]:
if target != votee:
prots = deque(var.ACTIVE_PROTECTIONS[target])
while len(prots) > 0:
# an event can read the current active protection and cancel the totem
# if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
# so that it cannot be used again (if the protection is meant to be usable once-only)
desp_evt = Event("desperation_totem", {})
if not desp_evt.dispatch(cli, var, votee, target, prots[0]):
return
prots.popleft()
if var.ROLE_REVEAL in ("on", "team"):
r1 = get_reveal_role(target)
an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
@ -464,8 +469,17 @@ def on_transition_day_resolve6(evt, cli, var, victim):
evt.data["message"].extend(ret_evt.data["message"])
if loser in evt.data["dead"] or victim == loser:
loser = None
# TODO: when blessed is split off, roll that check into retribution_kill
if loser is not None and loser not in var.ROLES["blessed villager"]:
if loser is not None:
prots = deque(var.ACTIVE_PROTECTIONS[loser])
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(cli, 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)
@ -551,6 +565,14 @@ def on_lynch(evt, cli, var, nick):
pm(cli, nick, messages["totem_narcolepsy"])
evt.prevent_default = True
@event_listener("assassinate")
def on_assassinate(evt, cli, var, nick, target, prot):
if prot == "totem":
var.ACTIVE_PROTECTIONS[target].remove("totem")
evt.prevent_default = True
evt.stop_propagation = True
cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "totem"].format(nick, target))
@event_listener("myrole")
def on_myrole(evt, cli, var, nick):
role = evt.data["role"]

View File

@ -230,14 +230,16 @@ def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
prole = get_role(player)
if player == nick:
prole = actor_role
wevt = Event("wolflist", {"tags": set()})
wevt.dispatch(cli, var, player, actor)
tags = " ".join(wevt.data["tags"])
if prole in wcroles:
cursed = ""
if player in var.ROLES["cursed villager"]:
cursed = "cursed "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
if tags:
tags += " "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, tags, prole)
notify.append(player)
elif player in var.ROLES["cursed villager"]:
pl[i] = player + " (cursed)"
elif tags:
pl[i] = "{0} ({1})".format(player, tags)
mass_privmsg(cli, notify, messages["players_exchanged_roles"].format(nick, actor))
evt.data["actor_messages"].append("Players: " + ", ".join(pl))
@ -256,14 +258,16 @@ def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role):
prole = get_role(player)
if player == actor:
prole = nick_role
wevt = Event("wolflist", {"tags": set()})
wevt.dispatch(cli, var, player, nick)
tags = " ".join(wevt.data["tags"])
if prole in wcroles:
cursed = ""
if player in var.ROLES["cursed villager"]:
cursed = "cursed "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
if tags:
tags += " "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, tags, prole)
notify.append(player)
elif player in var.ROLES["cursed villager"]:
pl[i] = player + " (cursed)"
elif tags:
pl[i] = "{0} ({1})".format(player, tags)
mass_privmsg(cli, notify, messages["players_exchanged_roles"].format(actor, nick))
evt.data["nick_messages"].append("Players: " + ", ".join(pl))
@ -333,34 +337,36 @@ def on_transition_night_end(evt, cli, var):
talkroles = var.WOLF_ROLES | {"traitor"}
for wolf in wolves:
# should make the cursed information an event that cursedvillager can then add to
# (e.g. an event to change what prefixes are sent with the role message, and a
# 2nd event to change information in parens in player list)
normal_notify = wolf in var.PLAYERS and not is_user_simple(wolf)
role = get_role(wolf)
cursed = "cursed " if wolf in var.ROLES["cursed villager"] and role in wcroles else ""
wevt = Event("wolflist", {"tags": set()})
tags = ""
if role in wcroles:
wevt.dispatch(cli, var, wolf, wolf)
tags = " ".join(wevt.data["tags"])
if normal_notify:
msg = "{0}_notify".format(role.replace(" ", "_"))
cmsg = "cursed_" + msg
try:
if cursed:
try:
pm(cli, wolf, messages[cmsg])
except KeyError:
pm(cli, wolf, messages[msg].format(cursed))
else:
pm(cli, wolf, messages[msg].format(cursed))
except KeyError:
# catchall in case we forgot something above
an = 'n' if role.startswith(("a", "e", "i", "o", "u")) else ""
pm(cli, wolf, messages["undefined_role_notify"].format(an, role))
if "cursed" in wevt.data["tags"]:
try:
tags2 = " ".join(wevt.data["tags"] - {"cursed"})
pm(cli, wolf, messages[cmsg].format(tags2))
except KeyError:
pm(cli, wolf, messages[msg].format(tags))
else:
pm(cli, wolf, messages[msg].format(tags))
if len(wolves) > 1 and wccond is not None and role in talkroles:
pm(cli, wolf, messages["wolfchat_notify"].format(wccond))
else:
an = "n" if cursed == "" and role.startswith(("a", "e", "i", "o", "u")) else ""
pm(cli, wolf, messages["wolf_simple"].format(an, cursed, role)) # !simple
an = ""
if tags:
if tags.startswith(("a", "e", "i", "o", "u")):
an = "n"
elif role.startswith(("a", "e", "i", "o", "u")):
an = "n"
pm(cli, wolf, messages["wolf_simple"].format(an, tags, role)) # !simple
pl = ps[:]
random.shuffle(pl)
@ -368,14 +374,17 @@ def on_transition_night_end(evt, cli, var):
if role in wcroles:
for i, player in enumerate(pl):
prole = get_role(player)
wevt.data["tags"] = set()
wevt.dispatch(cli, var, player, wolf)
tags = " ".join(wevt.data["tags"])
if prole in wcroles:
cursed = ""
if player in var.ROLES["cursed villager"]:
cursed = "cursed "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
elif player in var.ROLES["cursed villager"]:
pl[i] = player + " (cursed)"
if tags:
tags += " "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, tags, prole)
elif tags:
pl[i] = "{0} ({1})".format(player, tags)
elif role == "warlock":
# warlock specifically only sees cursed if they're not in wolfchat
for i, player in enumerate(pl):
if player in var.ROLES["cursed villager"]:
pl[i] = player + " (cursed)"

View File

@ -36,7 +36,7 @@ import threading
import time
import traceback
import urllib.request
from collections import defaultdict
from collections import defaultdict, deque
from datetime import datetime, timedelta
from oyoyo.parse import parse_nick
@ -1420,14 +1420,17 @@ def stats(cli, nick, chan, rest):
if role in badguys:
for i, player in enumerate(ps):
prole = get_role(player)
wevt = Event("wolflist", {"tags": set()})
wevt.dispatch(cli, var, player, nick)
tags = " ".join(wevt.data["tags"])
if prole in badguys:
cursed = ""
if player in var.ROLES["cursed villager"]:
cursed = "cursed "
ps[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
elif player in var.ROLES["cursed villager"]:
ps[i] = player + " (cursed)"
if tags:
tags += " "
ps[i] = "\u0002{0}\u0002 ({1}{2})".format(player, tags, prole)
elif tags:
ps[i] = "{0} ({1})".format(player, tags)
elif role == "warlock":
# warlock not in wolfchat explicitly only sees cursed
for i, player in enumerate(pl):
if player in var.ROLES["cursed villager"]:
ps[i] = player + " (cursed)"
@ -2823,10 +2826,12 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
random.shuffle(wolves)
for i, wolf in enumerate(wolves):
wolfrole = get_role(wolf)
cursed = ""
if wolf in var.ROLES["cursed villager"]:
cursed = "cursed "
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, cursed, wolfrole)
wevt = Event("wolflist", {"tags": set()})
wevt.dispatch(cli, var, wolf, clone)
tags = " ".join(wevt.data["tags"])
if tags:
tags += " "
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, tags, wolfrole)
if len(wolves):
pm(cli, clone, "Wolves: " + ", ".join(wolves))
@ -2862,32 +2867,28 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
if nick in var.TARGETED:
target = var.TARGETED[nick]
del var.TARGETED[nick]
if target != None and target in pl:
# TODO: split this off into an event so that individual roles can handle it as needed
if "totem" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
var.ACTIVE_PROTECTIONS[target].remove("totem")
message = messages["assassin_fail_totem"].format(nick, target)
cli.msg(botconfig.CHANNEL, message)
elif "angel" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
var.ACTIVE_PROTECTIONS[target].remove("angel")
message = messages["assassin_fail_angel"].format(nick, target)
cli.msg(botconfig.CHANNEL, message)
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
from src.roles import angel
for ga in var.ROLES["bodyguard"]:
if angel.GUARDED.get(ga) == target:
message = messages["assassin_fail_bodyguard"].format(nick, target, ga)
cli.msg(botconfig.CHANNEL, message)
del_player(cli, ga, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False)
pl = refresh_pl(pl)
break
elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]):
if "blessing" in var.ACTIVE_PROTECTIONS[target]:
var.ACTIVE_PROTECTIONS[target].remove("blessing")
# don't message the channel whenever a blessing blocks a kill, but *do* let the assassin know so they don't try to report it as a bug
pm(cli, nick, messages["assassin_fail_blessed"].format(target))
else:
if target is not None and target in pl:
prots = deque(var.ACTIVE_PROTECTIONS[target])
aevt = Event("assassinate", {"pl": pl},
del_player=del_player,
deadlist=deadlist,
original=original,
refresh_pl=refresh_pl,
message_prefix="assassin_fail_")
while len(prots) > 0:
# FA bypasses all protection (TODO: split off)
# when split instead of setting prots to [] will need to stop_propagation but NOT prevent_default
if nickrole == "fallen angel":
prots = []
break
# an event can read the current active protection and cancel the totem
# if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS
# so that it cannot be used again (if the protection is meant to be usable once-only)
if not aevt.dispatch(cli, var, nick, target, prots[0]):
pl = aevt.data["pl"]
break
prots.popleft()
if len(prots) == 0:
if var.ROLE_REVEAL in ("on", "team"):
role = get_reveal_role(target)
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
@ -3691,7 +3692,6 @@ def begin_day(cli):
var.LUCKY = set()
var.DISEASED = set()
var.MISDIRECTED = set()
var.ACTIVE_PROTECTIONS = defaultdict(list)
var.ENTRANCED_DYING = set()
var.DYING = set()
@ -3862,6 +3862,7 @@ def transition_day(cli, gameid=0):
# 2 = non-wolf kills
# 3 = fixing killers dict to have correct priority (wolf-side VG kills -> non-wolf kills -> wolf kills)
# 4 = protections/fallen angel
# 4.1 = shaman, 4.2 = bodyguard/GA, 4.3 = blessed villager, 4.8 = fallen angel
# 5 = alpha wolf bite, other custom events that trigger after all protection stuff is resolved
# 6 = rearranging victim list (ensure bodyguard/harlot messages plays),
# fixing killers dict priority again (in case step 4 or 5 added to it)
@ -3898,25 +3899,14 @@ def transition_day(cli, gameid=0):
# Logic out stacked kills and protections. If we get down to 1 kill remaining that is valid and the victim is in bywolves,
# we re-add them to onlybywolves to indicate that the other kill attempts were guarded against (and the wolf kill is what went through)
# If protections >= kills, we keep track of which protection message to show (prot totem > GA > bodyguard > blessing)
# TODO: split out adding people back to onlybywolves as part of splitting off FA
pl = list_players()
for v in pl:
if v in victims_set:
if v in var.DYING:
continue # bypass protections
if v in var.ROLES["blessed villager"]:
numkills[v] -= 1
if numkills[v] >= 0:
killers[v].pop(0)
if numkills[v] <= 0 and v not in protected:
protected[v] = "blessing"
elif numkills[v] <= 0:
var.ACTIVE_PROTECTIONS[v].append("blessing")
continue # dying by themselves, not killed by wolves
if numkills[v] == 1 and v in bywolves:
onlybywolves.add(v)
else:
# player wasn't targeted, but apply protections on them
if v in var.ROLES["blessed villager"]:
var.ACTIVE_PROTECTIONS[v].append("blessing")
fallenkills = set()
brokentotem = set()
@ -4145,11 +4135,6 @@ def transition_day(cli, gameid=0):
if victim not in revt.data["bitten"]:
revt.data["message"].append(messages["target_not_home"])
revt.data["novictmsg"] = False
elif revt.data["protected"].get(victim) == "blessing":
# don't play any special message for a blessed target, this means in a game with priest and monster it's not really possible
# for wolves to tell which is which. May want to change that in the future to be more obvious to wolves since there's not really
# any good reason to hide that info from them. In any case, we don't want to say the blessed person was attacked to the channel
continue
elif (victim in var.ROLES["lycan"] or victim in var.LYCANTHROPES) and victim in revt.data["onlybywolves"] and victim not in var.IMMUNIZED:
vrole = get_role(victim)
if vrole not in var.WOLFCHAT_ROLES:
@ -4166,10 +4151,12 @@ def transition_day(cli, gameid=0):
for i, wolf in enumerate(wolves):
pm(cli, wolf, messages["lycan_wc_notification"].format(victim))
role = get_role(wolf)
cursed = ""
if wolf in var.ROLES["cursed villager"]:
cursed = "cursed "
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, cursed, role)
wevt = Event("wolflist", {"tags": set()})
wevt.dispatch(cli, var, wolf, victim)
tags = " ".join(wevt.data["tags"])
if tags:
tags += " "
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, tags, role)
pm(cli, victim, "Wolves: " + ", ".join(wolves))
revt.data["novictmsg"] = False
@ -6052,12 +6039,6 @@ def transition_night(cli):
pm(cli, minion, messages["minion_simple"])
pm(cli, minion, "Wolves: " + ", ".join(wolves))
for blessed in var.ROLES["blessed villager"]:
if blessed in var.PLAYERS and not is_user_simple(blessed):
pm(cli, blessed, messages["blessed_notify"])
else:
pm(cli, blessed, messages["blessed_simple"])
for g in var.GUNNERS.keys():
if g not in ps:
continue
@ -7116,10 +7097,6 @@ def myrole(cli, nick, chan, rest):
if nick in var.ROLES["assassin"] and nick not in var.ROLES["amnesiac"]:
pm(cli, nick, messages["assassin_role_info"].format(messages["assassin_targeting"].format(var.TARGETED[nick]) if nick in var.TARGETED else ""))
# Remind blessed villager of their role
if nick in var.ROLES["blessed villager"]:
pm(cli, nick, messages["blessed_simple"])
# Remind prophet of their role, in sleepy mode only where it is hacked into a template instead of a role
if "prophet" in var.TEMPLATE_RESTRICTIONS and nick in var.ROLES["prophet"]:
pm(cli, nick, messages["prophet_simple"])