Split blessed and cursed villager
This commit is contained in:
parent
f5d510374a
commit
01dfdc7ac4
@ -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
91
src/roles/blessed.py
Normal 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
25
src/roles/cursed.py
Normal 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:
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
|
@ -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)"
|
||||
|
117
src/wolfgame.py
117
src/wolfgame.py
@ -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"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user